From 330ac0b218f6ec11ab233595b6bd708925812e71 Mon Sep 17 00:00:00 2001 From: Andreas Bernstein Date: Wed, 30 Oct 2013 08:13:20 -0700 Subject: [PATCH 01/96] Initial commit --- .gitignore | 13 +++++++++++++ README.md | 4 ++++ 2 files changed, 17 insertions(+) create mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..620d3dc8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Compiled Object files +*.slo +*.lo +*.o + +# Compiled Dynamic libraries +*.so +*.dylib + +# Compiled Static libraries +*.lai +*.la +*.a diff --git a/README.md b/README.md new file mode 100644 index 00000000..3ddf5d9b --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +avango +====== + +AVANGO is a free software framework designed for interactive, distributed applications. It supports a large range of displays from standard desktop applications to large-scale immersive Virtual Reality installations. From ccdc9c85042d063586bd17c9f00d06582a95621a Mon Sep 17 00:00:00 2001 From: Andre Schollmeyer Date: Mon, 4 Nov 2013 11:21:22 +0100 Subject: [PATCH 02/96] - initial commit includes only the modules core, daemon and unittests - exchanged scons by cmake --- CMakeLists.txt | 136 ++ avango-core/CMakeLists.txt | 116 ++ avango-core/include/avango/Action.h | 104 ++ avango-core/include/avango/Application.h | 161 ++ avango-core/include/avango/Assert.h | 88 + avango-core/include/avango/Base.h | 316 ++++ avango-core/include/avango/Config.h | 63 + avango-core/include/avango/Config.h.in | 63 + avango-core/include/avango/ContainerPool.h | 201 +++ avango-core/include/avango/Create.h | 113 ++ avango-core/include/avango/Distributed.h | 155 ++ avango-core/include/avango/Doxygen.h | 44 + avango-core/include/avango/Field.h | 354 ++++ avango-core/include/avango/FieldContainer.h | 358 ++++ .../include/avango/FieldContainerHelper.h | 48 + avango-core/include/avango/FieldRef.h | 63 + avango-core/include/avango/Init.h | 52 + avango-core/include/avango/InputStream.h | 155 ++ avango-core/include/avango/Link.h | 336 ++++ avango-core/include/avango/Logger.h | 31 + avango-core/include/avango/MaestroEID.h | 135 ++ avango-core/include/avango/Msg.h | 251 +++ avango-core/include/avango/MultiField.h | 463 ++++++ avango-core/include/avango/NetID.h | 96 ++ avango-core/include/avango/NetInfo.h | 65 + avango-core/include/avango/NetLock.h | 72 + avango-core/include/avango/NetMap.h | 87 + avango-core/include/avango/NetNode.h | 281 ++++ avango-core/include/avango/Object.h | 24 + avango-core/include/avango/ObjectValue.h | 120 ++ avango-core/include/avango/OutputStream.h | 164 ++ avango-core/include/avango/Reader.h | 74 + avango-core/include/avango/SConscript | 73 + avango-core/include/avango/Semaphore.h | 129 ++ avango-core/include/avango/SingleField.h | 361 ++++ avango-core/include/avango/Singleton.h | 176 ++ avango-core/include/avango/StandardFields.h | 90 + avango-core/include/avango/TimeSensor.h | 77 + avango-core/include/avango/Type.h | 313 ++++ avango-core/include/avango/Typed.h | 222 +++ avango-core/include/avango/WriteAction.h | 147 ++ avango-core/include/avango/logging/Appender.h | 67 + avango-core/include/avango/logging/Config.h | 46 + .../include/avango/logging/ConsoleAppender.h | 72 + .../include/avango/logging/FileAppender.h | 84 + avango-core/include/avango/logging/Level.h | 91 ++ avango-core/include/avango/logging/Logger.h | 424 +++++ .../include/avango/logging/LoggerManager.h | 88 + .../include/avango/logging/LoggingEvent.h | 101 ++ avango-core/include/avango/logging/SConscript | 38 + .../include/avango/logging/StreamAppender.h | 75 + .../include/avango/stdint_replacement.h | 44 + avango-core/include/avango/windows_specific.h | 44 + avango-core/src/avango/Init.cpp | 52 + avango-core/src/avango/actions/Action.cpp | 85 + .../src/avango/actions/WriteAction.cpp | 209 +++ avango-core/src/avango/fields/Field.cpp | 725 +++++++++ avango-core/src/avango/fields/MultiField.cpp | 390 +++++ avango-core/src/avango/fields/SingleField.cpp | 302 ++++ .../src/avango/fields/StandardFields.cpp | 82 + .../avango/fields/tests/TestCloneFields.cpp | 76 + .../avango/fields/tests/TestFieldConst.cpp | 84 + .../fields/tests/TestFieldMultiPush.cpp | 137 ++ .../fields/tests/TestFieldReferencing.cpp | 126 ++ .../fields/tests/TestFieldTypeConversion.cpp | 202 +++ .../fields/tests/TestFieldValueCallbacks.cpp | 133 ++ .../src/avango/fields/tests/TestFields.cpp | 36 + .../avango/fields/tests/TestMultiFields.cpp | 186 +++ .../src/avango/interface/Application.cpp | 207 +++ .../avango/interface/FieldContainerHelper.cpp | 42 + .../src/avango/interface/TimeSensor.cpp | 94 ++ .../interface/tests/TestApplication.cpp | 123 ++ .../avango/interface/tests/TestTimeSensor.cpp | 68 + .../src/avango/logging/ConsoleAppender.cpp | 37 + .../src/avango/logging/FileAppender.cpp | 56 + avango-core/src/avango/logging/Level.cpp | 44 + avango-core/src/avango/logging/Logger.cpp | 288 ++++ .../src/avango/logging/LoggerManager.cpp | 120 ++ .../src/avango/logging/LoggingEvent.cpp | 97 ++ .../src/avango/logging/StreamAppender.cpp | 42 + .../src/avango/logging/tests/TestLogging.cpp | 241 +++ avango-core/src/avango/network/CMakeLists.txt | 17 + avango-core/src/avango/network/Helper.cpp | 51 + avango-core/src/avango/network/Helper.h | 39 + avango-core/src/avango/network/MaestroEID.cpp | 244 +++ .../src/avango/network/MaestroMerge.cpp | 524 ++++++ avango-core/src/avango/network/MaestroMerge.h | 209 +++ avango-core/src/avango/network/Msg.cpp | 717 ++++++++ avango-core/src/avango/network/NetGroup.cpp | 228 +++ avango-core/src/avango/network/NetGroup.h | 103 ++ avango-core/src/avango/network/NetID.cpp | 120 ++ avango-core/src/avango/network/NetInfo.cpp | 103 ++ avango-core/src/avango/network/NetLock.cpp | 84 + avango-core/src/avango/network/NetMap.cpp | 378 +++++ avango-core/src/avango/network/NetNode.cpp | 1256 ++++++++++++++ .../src/avango/network/NetNodeClient.cpp | 102 ++ .../src/avango/network/NetNodeClient.h | 72 + .../src/avango/network/NetNodeServer.cpp | 56 + .../src/avango/network/NetNodeServer.h | 61 + .../src/avango/network/UpcallSerializer.cpp | 320 ++++ .../src/avango/network/UpcallSerializer.h | 285 ++++ .../src/avango/network/tests/TestNetLock.cpp | 73 + .../src/avango/network/tests/TestNetNode.cpp | 130 ++ .../src/avango/network/tests/TestNetwork.cpp | 41 + avango-core/src/avango/nodes/Base.cpp | 240 +++ avango-core/src/avango/nodes/Distributed.cpp | 168 ++ .../src/avango/nodes/FieldContainer.cpp | 754 +++++++++ avango-core/src/avango/nodes/ObjectValue.cpp | 47 + avango-core/src/avango/nodes/Typed.cpp | 93 ++ .../avango/nodes/tests/MockFieldContainer.cpp | 49 + .../avango/nodes/tests/MockFieldContainer.h | 59 + .../avango/nodes/tests/TestAbstractNode.cpp | 138 ++ .../src/avango/nodes/tests/TestEvaluation.cpp | 95 ++ .../nodes/tests/TestEvaluationOrder.cpp | 240 +++ .../TestFieldConnectionChangeInNotify.cpp | 122 ++ .../avango/nodes/tests/TestFieldContainer.cpp | 105 ++ .../src/avango/nodes/tests/TestNodes.cpp | 37 + .../src/avango/nodes/tests/TestUnref.cpp | 146 ++ .../src/avango/streams/InputStream.cpp | 212 +++ .../src/avango/streams/OutputStream.cpp | 208 +++ avango-core/src/avango/streams/Reader.cpp | 184 +++ avango-core/src/avango/support/Assert.cpp | 67 + avango-core/src/avango/support/Semaphore.cpp | 80 + .../src/avango/types/ContainerPool.cpp | 375 +++++ avango-core/src/avango/types/Create.cpp | 71 + avango-core/src/avango/types/Link.cpp | 202 +++ avango-core/src/avango/types/Type.cpp | 442 +++++ .../avango/types/tests/TestContainerPool.cpp | 53 + .../src/avango/types/tests/TestLibType.cpp | 48 + .../src/avango/types/tests/TestType.cpp | 115 ++ avango-daemon/CMakeLists.txt | 53 + avango-daemon/include/avango/daemon/Config.h | 49 + .../include/avango/daemon/Config.h.in | 49 + avango-daemon/include/avango/daemon/DTrack.h | 101 ++ avango-daemon/include/avango/daemon/Device.h | 183 +++ .../include/avango/daemon/DeviceActuator.h | 88 + .../include/avango/daemon/DeviceDaemon.h | 88 + .../include/avango/daemon/DeviceSensor.h | 241 +++ .../include/avango/daemon/DeviceService.h | 142 ++ avango-daemon/include/avango/daemon/Doxygen.h | 44 + .../include/avango/daemon/HIDInput.h | 250 +++ avango-daemon/include/avango/daemon/Init.h | 53 + .../include/avango/daemon/LinuxEvent.h | 63 + .../avango/daemon/SharedMemorySegment.h | 90 + avango-daemon/include/avango/daemon/Station.h | 124 ++ .../include/avango/daemon/StationBlock.h | 99 ++ .../include/avango/daemon/StationSegment.h | 88 + .../include/avango/daemon/VRPNClient.h | 125 ++ .../include/avango/daemon/WacomTablet.h | 101 ++ avango-daemon/include/avango/daemon/Wiimote.h | 84 + .../include/avango/daemon/WiimoteActuator.h | 87 + avango-daemon/python/__init__.py | 216 +++ avango-daemon/python/_daemon.cpp | 228 +++ avango-daemon/src/avango/daemon/DTrack.cpp | 286 ++++ avango-daemon/src/avango/daemon/Device.cpp | 127 ++ .../src/avango/daemon/DeviceActuator.cpp | 65 + .../src/avango/daemon/DeviceDaemon.cpp | 105 ++ .../src/avango/daemon/DeviceSensor.cpp | 257 +++ .../src/avango/daemon/DeviceService.cpp | 303 ++++ avango-daemon/src/avango/daemon/HIDInput.cpp | 1449 +++++++++++++++++ avango-daemon/src/avango/daemon/Init.cpp | 75 + .../src/avango/daemon/LinuxEvent.cpp | 520 ++++++ .../src/avango/daemon/SharedMemorySegment.cpp | 274 ++++ avango-daemon/src/avango/daemon/Station.cpp | 200 +++ .../src/avango/daemon/StationBlock.cpp | 74 + .../src/avango/daemon/StationSegment.cpp | 61 + .../src/avango/daemon/VRPNClient.cpp | 184 +++ .../src/avango/daemon/WacomTablet.cpp | 263 +++ avango-daemon/src/avango/daemon/Wiimote.cpp | 114 ++ .../src/avango/daemon/WiimoteActuator.cpp | 115 ++ .../src/avango/daemon/dtrack/dtrack.cpp | 803 +++++++++ .../src/avango/daemon/dtrack/dtrack.h | 199 +++ .../daemon/tests/TestApplicationSide.cpp | 47 + .../avango/daemon/tests/TestAvangoDaemon.cpp | 42 + .../avango/daemon/tests/TestDaemonSide.cpp | 53 + avango-daemon/src/examples/README | 41 + avango-daemon/src/examples/TestDevice.cpp | 63 + avango-daemon/src/examples/devices.scm | 20 + avango-unittest/CMakeLists.txt | 136 ++ .../dist/pkg-config/avango-unittest.pc.in | 10 + .../avango/UnitTest++/AssertException.h | 28 + .../include/avango/UnitTest++/CheckMacros.h | 102 ++ .../include/avango/UnitTest++/Checks.h | 146 ++ .../include/avango/UnitTest++/Config.h | 25 + .../avango/UnitTest++/DeferredTestReporter.h | 28 + .../avango/UnitTest++/DeferredTestResult.h | 29 + .../avango/UnitTest++/MemoryOutStream.h | 67 + .../UnitTest++/Posix/SignalTranslator.h | 42 + .../avango/UnitTest++/Posix/TimeHelpers.h | 28 + .../include/avango/UnitTest++/ReportAssert.h | 10 + .../include/avango/UnitTest++/Test.h | 34 + .../include/avango/UnitTest++/TestDetails.h | 24 + .../include/avango/UnitTest++/TestList.h | 32 + .../include/avango/UnitTest++/TestMacros.h | 99 ++ .../include/avango/UnitTest++/TestReporter.h | 20 + .../avango/UnitTest++/TestReporterStdout.h | 19 + .../include/avango/UnitTest++/TestResults.h | 36 + .../include/avango/UnitTest++/TestRunner.h | 17 + .../include/avango/UnitTest++/TestSuite.h | 14 + .../avango/UnitTest++/TimeConstraint.h | 34 + .../include/avango/UnitTest++/TimeHelpers.h | 7 + .../include/avango/UnitTest++/UnitTest++.h | 17 + .../avango/UnitTest++/Win32/TimeHelpers.h | 48 + .../avango/UnitTest++/XmlTestReporter.h | 34 + .../src/avango/UnitTest++/AssertException.cpp | 32 + avango-unittest/src/avango/UnitTest++/COPYING | 20 + .../src/avango/UnitTest++/Checks.cpp | 48 + .../UnitTest++/DeferredTestReporter.cpp | 28 + .../avango/UnitTest++/DeferredTestResult.cpp | 26 + .../src/avango/UnitTest++/MemoryOutStream.cpp | 143 ++ .../UnitTest++/Posix/SignalTranslator.cpp | 46 + .../avango/UnitTest++/Posix/TimeHelpers.cpp | 33 + avango-unittest/src/avango/UnitTest++/README | 57 + .../src/avango/UnitTest++/ReportAssert.cpp | 12 + .../src/avango/UnitTest++/Test.cpp | 62 + .../src/avango/UnitTest++/TestDetails.cpp | 22 + .../src/avango/UnitTest++/TestList.cpp | 39 + .../src/avango/UnitTest++/TestReporter.cpp | 10 + .../avango/UnitTest++/TestReporterStdout.cpp | 36 + .../src/avango/UnitTest++/TestResults.cpp | 60 + .../src/avango/UnitTest++/TestRunner.cpp | 60 + .../src/avango/UnitTest++/TimeConstraint.cpp | 28 + .../avango/UnitTest++/Win32/TimeHelpers.cpp | 46 + .../src/avango/UnitTest++/XmlTestReporter.cpp | 126 ++ .../avango/UnitTest++/docs/UnitTest++.html | 260 +++ .../src/avango/UnitTest++/tests/Main.cpp | 8 + .../UnitTest++/tests/RecordingReporter.h | 92 ++ .../UnitTest++/tests/TestAssertHandler.cpp | 44 + .../UnitTest++/tests/TestCheckMacros.cpp | 710 ++++++++ .../avango/UnitTest++/tests/TestChecks.cpp | 290 ++++ .../tests/TestDeferredTestReporter.cpp | 104 ++ .../UnitTest++/tests/TestMemoryOutStream.cpp | 150 ++ .../src/avango/UnitTest++/tests/TestTest.cpp | 97 ++ .../avango/UnitTest++/tests/TestTestList.cpp | 50 + .../UnitTest++/tests/TestTestMacros.cpp | 171 ++ .../UnitTest++/tests/TestTestResults.cpp | 111 ++ .../UnitTest++/tests/TestTestRunner.cpp | 233 +++ .../avango/UnitTest++/tests/TestTestSuite.cpp | 13 + .../UnitTest++/tests/TestTimeConstraint.cpp | 57 + .../tests/TestTimeConstraintMacro.cpp | 29 + .../UnitTest++/tests/TestUnitTest++.cpp | 137 ++ .../UnitTest++/tests/TestXmlTestReporter.cpp | 183 +++ cmake/modules/find_boost.cmake | 166 ++ cmake/modules/find_compiler.cmake | 47 + 244 files changed, 34756 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 avango-core/CMakeLists.txt create mode 100644 avango-core/include/avango/Action.h create mode 100644 avango-core/include/avango/Application.h create mode 100644 avango-core/include/avango/Assert.h create mode 100644 avango-core/include/avango/Base.h create mode 100644 avango-core/include/avango/Config.h create mode 100644 avango-core/include/avango/Config.h.in create mode 100644 avango-core/include/avango/ContainerPool.h create mode 100644 avango-core/include/avango/Create.h create mode 100644 avango-core/include/avango/Distributed.h create mode 100644 avango-core/include/avango/Doxygen.h create mode 100644 avango-core/include/avango/Field.h create mode 100644 avango-core/include/avango/FieldContainer.h create mode 100644 avango-core/include/avango/FieldContainerHelper.h create mode 100644 avango-core/include/avango/FieldRef.h create mode 100644 avango-core/include/avango/Init.h create mode 100644 avango-core/include/avango/InputStream.h create mode 100644 avango-core/include/avango/Link.h create mode 100644 avango-core/include/avango/Logger.h create mode 100644 avango-core/include/avango/MaestroEID.h create mode 100644 avango-core/include/avango/Msg.h create mode 100644 avango-core/include/avango/MultiField.h create mode 100644 avango-core/include/avango/NetID.h create mode 100644 avango-core/include/avango/NetInfo.h create mode 100644 avango-core/include/avango/NetLock.h create mode 100644 avango-core/include/avango/NetMap.h create mode 100644 avango-core/include/avango/NetNode.h create mode 100644 avango-core/include/avango/Object.h create mode 100644 avango-core/include/avango/ObjectValue.h create mode 100644 avango-core/include/avango/OutputStream.h create mode 100644 avango-core/include/avango/Reader.h create mode 100644 avango-core/include/avango/SConscript create mode 100644 avango-core/include/avango/Semaphore.h create mode 100644 avango-core/include/avango/SingleField.h create mode 100644 avango-core/include/avango/Singleton.h create mode 100644 avango-core/include/avango/StandardFields.h create mode 100644 avango-core/include/avango/TimeSensor.h create mode 100644 avango-core/include/avango/Type.h create mode 100644 avango-core/include/avango/Typed.h create mode 100644 avango-core/include/avango/WriteAction.h create mode 100644 avango-core/include/avango/logging/Appender.h create mode 100644 avango-core/include/avango/logging/Config.h create mode 100644 avango-core/include/avango/logging/ConsoleAppender.h create mode 100644 avango-core/include/avango/logging/FileAppender.h create mode 100644 avango-core/include/avango/logging/Level.h create mode 100644 avango-core/include/avango/logging/Logger.h create mode 100644 avango-core/include/avango/logging/LoggerManager.h create mode 100644 avango-core/include/avango/logging/LoggingEvent.h create mode 100644 avango-core/include/avango/logging/SConscript create mode 100644 avango-core/include/avango/logging/StreamAppender.h create mode 100644 avango-core/include/avango/stdint_replacement.h create mode 100644 avango-core/include/avango/windows_specific.h create mode 100644 avango-core/src/avango/Init.cpp create mode 100644 avango-core/src/avango/actions/Action.cpp create mode 100644 avango-core/src/avango/actions/WriteAction.cpp create mode 100644 avango-core/src/avango/fields/Field.cpp create mode 100644 avango-core/src/avango/fields/MultiField.cpp create mode 100644 avango-core/src/avango/fields/SingleField.cpp create mode 100644 avango-core/src/avango/fields/StandardFields.cpp create mode 100644 avango-core/src/avango/fields/tests/TestCloneFields.cpp create mode 100644 avango-core/src/avango/fields/tests/TestFieldConst.cpp create mode 100644 avango-core/src/avango/fields/tests/TestFieldMultiPush.cpp create mode 100644 avango-core/src/avango/fields/tests/TestFieldReferencing.cpp create mode 100644 avango-core/src/avango/fields/tests/TestFieldTypeConversion.cpp create mode 100644 avango-core/src/avango/fields/tests/TestFieldValueCallbacks.cpp create mode 100644 avango-core/src/avango/fields/tests/TestFields.cpp create mode 100644 avango-core/src/avango/fields/tests/TestMultiFields.cpp create mode 100644 avango-core/src/avango/interface/Application.cpp create mode 100644 avango-core/src/avango/interface/FieldContainerHelper.cpp create mode 100644 avango-core/src/avango/interface/TimeSensor.cpp create mode 100644 avango-core/src/avango/interface/tests/TestApplication.cpp create mode 100644 avango-core/src/avango/interface/tests/TestTimeSensor.cpp create mode 100644 avango-core/src/avango/logging/ConsoleAppender.cpp create mode 100644 avango-core/src/avango/logging/FileAppender.cpp create mode 100644 avango-core/src/avango/logging/Level.cpp create mode 100644 avango-core/src/avango/logging/Logger.cpp create mode 100644 avango-core/src/avango/logging/LoggerManager.cpp create mode 100644 avango-core/src/avango/logging/LoggingEvent.cpp create mode 100644 avango-core/src/avango/logging/StreamAppender.cpp create mode 100644 avango-core/src/avango/logging/tests/TestLogging.cpp create mode 100644 avango-core/src/avango/network/CMakeLists.txt create mode 100644 avango-core/src/avango/network/Helper.cpp create mode 100644 avango-core/src/avango/network/Helper.h create mode 100644 avango-core/src/avango/network/MaestroEID.cpp create mode 100644 avango-core/src/avango/network/MaestroMerge.cpp create mode 100644 avango-core/src/avango/network/MaestroMerge.h create mode 100644 avango-core/src/avango/network/Msg.cpp create mode 100644 avango-core/src/avango/network/NetGroup.cpp create mode 100644 avango-core/src/avango/network/NetGroup.h create mode 100644 avango-core/src/avango/network/NetID.cpp create mode 100644 avango-core/src/avango/network/NetInfo.cpp create mode 100644 avango-core/src/avango/network/NetLock.cpp create mode 100644 avango-core/src/avango/network/NetMap.cpp create mode 100644 avango-core/src/avango/network/NetNode.cpp create mode 100644 avango-core/src/avango/network/NetNodeClient.cpp create mode 100644 avango-core/src/avango/network/NetNodeClient.h create mode 100644 avango-core/src/avango/network/NetNodeServer.cpp create mode 100644 avango-core/src/avango/network/NetNodeServer.h create mode 100644 avango-core/src/avango/network/UpcallSerializer.cpp create mode 100644 avango-core/src/avango/network/UpcallSerializer.h create mode 100644 avango-core/src/avango/network/tests/TestNetLock.cpp create mode 100644 avango-core/src/avango/network/tests/TestNetNode.cpp create mode 100644 avango-core/src/avango/network/tests/TestNetwork.cpp create mode 100644 avango-core/src/avango/nodes/Base.cpp create mode 100644 avango-core/src/avango/nodes/Distributed.cpp create mode 100644 avango-core/src/avango/nodes/FieldContainer.cpp create mode 100644 avango-core/src/avango/nodes/ObjectValue.cpp create mode 100644 avango-core/src/avango/nodes/Typed.cpp create mode 100644 avango-core/src/avango/nodes/tests/MockFieldContainer.cpp create mode 100644 avango-core/src/avango/nodes/tests/MockFieldContainer.h create mode 100644 avango-core/src/avango/nodes/tests/TestAbstractNode.cpp create mode 100644 avango-core/src/avango/nodes/tests/TestEvaluation.cpp create mode 100644 avango-core/src/avango/nodes/tests/TestEvaluationOrder.cpp create mode 100644 avango-core/src/avango/nodes/tests/TestFieldConnectionChangeInNotify.cpp create mode 100644 avango-core/src/avango/nodes/tests/TestFieldContainer.cpp create mode 100644 avango-core/src/avango/nodes/tests/TestNodes.cpp create mode 100644 avango-core/src/avango/nodes/tests/TestUnref.cpp create mode 100644 avango-core/src/avango/streams/InputStream.cpp create mode 100644 avango-core/src/avango/streams/OutputStream.cpp create mode 100644 avango-core/src/avango/streams/Reader.cpp create mode 100644 avango-core/src/avango/support/Assert.cpp create mode 100644 avango-core/src/avango/support/Semaphore.cpp create mode 100644 avango-core/src/avango/types/ContainerPool.cpp create mode 100644 avango-core/src/avango/types/Create.cpp create mode 100644 avango-core/src/avango/types/Link.cpp create mode 100644 avango-core/src/avango/types/Type.cpp create mode 100644 avango-core/src/avango/types/tests/TestContainerPool.cpp create mode 100644 avango-core/src/avango/types/tests/TestLibType.cpp create mode 100644 avango-core/src/avango/types/tests/TestType.cpp create mode 100644 avango-daemon/CMakeLists.txt create mode 100644 avango-daemon/include/avango/daemon/Config.h create mode 100644 avango-daemon/include/avango/daemon/Config.h.in create mode 100644 avango-daemon/include/avango/daemon/DTrack.h create mode 100644 avango-daemon/include/avango/daemon/Device.h create mode 100644 avango-daemon/include/avango/daemon/DeviceActuator.h create mode 100644 avango-daemon/include/avango/daemon/DeviceDaemon.h create mode 100644 avango-daemon/include/avango/daemon/DeviceSensor.h create mode 100644 avango-daemon/include/avango/daemon/DeviceService.h create mode 100644 avango-daemon/include/avango/daemon/Doxygen.h create mode 100644 avango-daemon/include/avango/daemon/HIDInput.h create mode 100644 avango-daemon/include/avango/daemon/Init.h create mode 100644 avango-daemon/include/avango/daemon/LinuxEvent.h create mode 100644 avango-daemon/include/avango/daemon/SharedMemorySegment.h create mode 100644 avango-daemon/include/avango/daemon/Station.h create mode 100644 avango-daemon/include/avango/daemon/StationBlock.h create mode 100644 avango-daemon/include/avango/daemon/StationSegment.h create mode 100644 avango-daemon/include/avango/daemon/VRPNClient.h create mode 100644 avango-daemon/include/avango/daemon/WacomTablet.h create mode 100644 avango-daemon/include/avango/daemon/Wiimote.h create mode 100644 avango-daemon/include/avango/daemon/WiimoteActuator.h create mode 100644 avango-daemon/python/__init__.py create mode 100644 avango-daemon/python/_daemon.cpp create mode 100644 avango-daemon/src/avango/daemon/DTrack.cpp create mode 100644 avango-daemon/src/avango/daemon/Device.cpp create mode 100644 avango-daemon/src/avango/daemon/DeviceActuator.cpp create mode 100644 avango-daemon/src/avango/daemon/DeviceDaemon.cpp create mode 100644 avango-daemon/src/avango/daemon/DeviceSensor.cpp create mode 100644 avango-daemon/src/avango/daemon/DeviceService.cpp create mode 100644 avango-daemon/src/avango/daemon/HIDInput.cpp create mode 100644 avango-daemon/src/avango/daemon/Init.cpp create mode 100644 avango-daemon/src/avango/daemon/LinuxEvent.cpp create mode 100644 avango-daemon/src/avango/daemon/SharedMemorySegment.cpp create mode 100644 avango-daemon/src/avango/daemon/Station.cpp create mode 100644 avango-daemon/src/avango/daemon/StationBlock.cpp create mode 100644 avango-daemon/src/avango/daemon/StationSegment.cpp create mode 100644 avango-daemon/src/avango/daemon/VRPNClient.cpp create mode 100644 avango-daemon/src/avango/daemon/WacomTablet.cpp create mode 100644 avango-daemon/src/avango/daemon/Wiimote.cpp create mode 100644 avango-daemon/src/avango/daemon/WiimoteActuator.cpp create mode 100644 avango-daemon/src/avango/daemon/dtrack/dtrack.cpp create mode 100644 avango-daemon/src/avango/daemon/dtrack/dtrack.h create mode 100644 avango-daemon/src/avango/daemon/tests/TestApplicationSide.cpp create mode 100644 avango-daemon/src/avango/daemon/tests/TestAvangoDaemon.cpp create mode 100644 avango-daemon/src/avango/daemon/tests/TestDaemonSide.cpp create mode 100644 avango-daemon/src/examples/README create mode 100644 avango-daemon/src/examples/TestDevice.cpp create mode 100644 avango-daemon/src/examples/devices.scm create mode 100644 avango-unittest/CMakeLists.txt create mode 100644 avango-unittest/dist/pkg-config/avango-unittest.pc.in create mode 100644 avango-unittest/include/avango/UnitTest++/AssertException.h create mode 100644 avango-unittest/include/avango/UnitTest++/CheckMacros.h create mode 100644 avango-unittest/include/avango/UnitTest++/Checks.h create mode 100644 avango-unittest/include/avango/UnitTest++/Config.h create mode 100644 avango-unittest/include/avango/UnitTest++/DeferredTestReporter.h create mode 100644 avango-unittest/include/avango/UnitTest++/DeferredTestResult.h create mode 100644 avango-unittest/include/avango/UnitTest++/MemoryOutStream.h create mode 100644 avango-unittest/include/avango/UnitTest++/Posix/SignalTranslator.h create mode 100644 avango-unittest/include/avango/UnitTest++/Posix/TimeHelpers.h create mode 100644 avango-unittest/include/avango/UnitTest++/ReportAssert.h create mode 100644 avango-unittest/include/avango/UnitTest++/Test.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestDetails.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestList.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestMacros.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestReporter.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestReporterStdout.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestResults.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestRunner.h create mode 100644 avango-unittest/include/avango/UnitTest++/TestSuite.h create mode 100644 avango-unittest/include/avango/UnitTest++/TimeConstraint.h create mode 100644 avango-unittest/include/avango/UnitTest++/TimeHelpers.h create mode 100644 avango-unittest/include/avango/UnitTest++/UnitTest++.h create mode 100644 avango-unittest/include/avango/UnitTest++/Win32/TimeHelpers.h create mode 100644 avango-unittest/include/avango/UnitTest++/XmlTestReporter.h create mode 100644 avango-unittest/src/avango/UnitTest++/AssertException.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/COPYING create mode 100644 avango-unittest/src/avango/UnitTest++/Checks.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/DeferredTestReporter.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/DeferredTestResult.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/MemoryOutStream.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/Posix/SignalTranslator.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/Posix/TimeHelpers.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/README create mode 100644 avango-unittest/src/avango/UnitTest++/ReportAssert.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/Test.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/TestDetails.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/TestList.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/TestReporter.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/TestReporterStdout.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/TestResults.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/TestRunner.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/TimeConstraint.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/Win32/TimeHelpers.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/XmlTestReporter.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/docs/UnitTest++.html create mode 100644 avango-unittest/src/avango/UnitTest++/tests/Main.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/RecordingReporter.h create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestAssertHandler.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestCheckMacros.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestChecks.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestDeferredTestReporter.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestMemoryOutStream.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTest.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestList.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestMacros.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestResults.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestRunner.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestSuite.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraint.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraintMacro.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestUnitTest++.cpp create mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestXmlTestReporter.cpp create mode 100644 cmake/modules/find_boost.cmake create mode 100644 cmake/modules/find_compiler.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..d7432686 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,136 @@ +################################################################ +# Avango +################################################################ +PROJECT(AVANGO CXX) + +# version number +set(AVANGO_MAJOR 1) +set(AVANGO_MINOR 0) +set(AVANGO_PATCH 0) +set(AVANGO_VERSION ${AVANGO_MAJOR}.${AVANGO_MINOR}.${AVANGO_PATCH}) +set(AVANGO_DESCRIPTION "AVANGO") +set(AVANGO_HOMEPAGE "https://github.com/vrsys") +set(AVANGO_EXENAME "AVANGO") +set(AVANGO_PACKAGENAME "AVANGO") + +# We require at least version 2.8.0 +cmake_minimum_required(VERSION 2.8.0) + +if (UNIX) + find_package(PkgConfig) +endif(UNIX) + +# Location where cmake first looks for modules. +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) + +################################################################ +# Configure and find libraries +################################################################ +set(GLOBAL_EXT_DIR ${AVANGO_SOURCE_DIR}/externals) + +MESSAGE(${GLOBAL_EXT_DIR}) + +if (UNIX) + pkg_check_modules(GL REQUIRED gl) +endif (UNIX) + +include(find_compiler) +include(find_boost) + +set(LIBRARIES + ${BOOST_LIBRARIES} + ${GL_LIBRARIES} +) + +set(LIB_PATHS + ${GL_LIBRARY_DIRS} + ${BOOST_LIBRARY_DIRS} +) + +set(INCLUDE_PATHS + ${CMAKE_CURRENT_SOURCE_DIR}/build + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${BOOST_INCLUDE_DIRS} + ${GL_INCLUDE_DIRS} +) + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + +################################################################ +# preprocessor configuration +################################################################ +IF (UNIX) + set(CMAKE_CXX_FLAGS_RELEASE "-s -O4 --std=c++0x -fpermissive") + set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall --std=c++0x -fpermissive") +ELSEIF(MSVC) + set(CMAKE_CXX_FLAGS_RELEASE "-D _SECURE_SCL=0 -D _SCL_SECURE_NO_WARNINGS -D _CRT_SECURE_NO_DEPRECATE /MD /MP") + set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG /MDd /Zi") +ENDIF(UNIX) + +################################################################ +# Avango Configuration +################################################################ +SET (AVANGO_VERSION_MAJOR "1" CACHE STRING "Major version of AvangoNG.") +SET (AVANGO_VERSION_MINOR "90" CACHE STRING "Minor version of AvangoNG.") +SET (AVANGO_VERSION_MAINT "0" CACHE STRING "Maintenance version of AvangoNG.") + +SET (AVANGO_DAEMON_DEBUG "false" CACHE BOOL "Enable Daemon debugging") +SET (AVANGO_DAEMON_VRPN_SUPPORT "false" CACHE BOOL "Enable VRPN support") +SET (AVANGO_DISTRIBUTION_SUPPORT "false" CACHE BOOL "Set to enable distribution support.") +SET (AVANGO_ZMQ_DISTRIBUTION_SUPPORT "false" CACHE BOOL "Set to use ZMQ for distribution.") +SET (AVANGO_PCL_SUPPORT "true" CACHE BOOL "Use PCL.") +SET (AVANGO_LOG_LEVEL "WARN" CACHE STRING "Set AvangoNG log level: FATAL, ERROR, WARN, INFO, DEBUG, TRACE") +SET (AVANGO_UNITTESTS "false" CACHE BOOL "Compile Unittests for Avango.") + +# enable daemon debugging +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_DAEMON_DEBUG") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_DAEMON_VRPN_SUPPORT=${AVANGO_DAEMON_VRPN_SUPPORT}") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_DISTRIBUTION_SUPPORT=${AVANGO_DISTRIBUTION_SUPPORT}") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_ZMQ_DISTRIBUTION_SUPPORT=${AVANGO_ZMQ_DISTRIBUTION_SUPPORT}") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_PCL_SUPPORT=${AVANGO_PCL_SUPPORT}") + + +# add DEBUG flag for debug built +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D DEFINE_AVANGO_DEBUG=1") + +# set debug log level and version strings +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_LOG_LEVEL=${AVANGO_LOG_LEVEL}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_VERSION_MAJOR=${AVANGO_VERSION_MAJOR}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_VERSION_MINOR=${AVANGO_VERSION_MINOR}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_VERSION_MAINT=${AVANGO_VERSION_MAINT}") + +IF (MSVC) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D AV_LIBRARY") +ENDIF (MSVC) + + +################################################################ +# Create libraries +################################################################ + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) +set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) + +add_subdirectory(avango-core) +add_subdirectory(avango-daemon) +#add_subdirectory(avango-python) + +################################################################ +# Summary +################################################################ + +message( "" ) +message( "Summary:" ) +message( " build type: ${CMAKE_BUILD_TYPE}" ) +message( "" ) +message( " boost:" ) +message( " library: ${BOOST_LIBRARIES}" ) +message( " library path: ${BOOST_LIBRARY_DIRS}" ) +message( " include: ${BOOST_INCLUDE_DIRS}" ) +message( "" ) +message( " gl:" ) +message( " library: ${GL_LIBRARIES}" ) +message( " include: ${GL_INCLUDE_DIRS}" ) +message( "" ) diff --git a/avango-core/CMakeLists.txt b/avango-core/CMakeLists.txt new file mode 100644 index 00000000..2de040b4 --- /dev/null +++ b/avango-core/CMakeLists.txt @@ -0,0 +1,116 @@ +# read replacement text from file +FILE(READ include/avango/Config.h.in AVANGO_CONFIG_IN) + +############################################################################### +# write Config.h +############################################################################### +SET(AVANGO_CONFIG_OUT ${AVANGO_CONFIG_IN}) + +STRING(REGEX MATCHALL "%\\([^\\)]+\\)s" AVANGO_CONFIG_VARIABLES ${AVANGO_CONFIG_IN}) + +FOREACH(_CUR_VARIABLE ${AVANGO_CONFIG_VARIABLES}) + SET(_STRIPPED_VARIABLE "") + STRING(REGEX REPLACE "%\\(" "" _STRIPPED_VARIABLE ${_CUR_VARIABLE}) + STRING(REGEX REPLACE "\\)s" "" _STRIPPED_VARIABLE ${_STRIPPED_VARIABLE}) + STRING(REPLACE ${_CUR_VARIABLE} _${_STRIPPED_VARIABLE} AVANGO_CONFIG_OUT ${AVANGO_CONFIG_OUT}) +ENDFOREACH(_CUR_VARIABLE) + +STRING(REPLACE "av::logging::_AVANGO_LOG_LEVEL" "av::logging::${AVANGO_LOG_LEVEL}" AVANGO_CONFIG_OUT ${AVANGO_CONFIG_OUT}) + +FILE(WRITE include/avango/Config.h ${AVANGO_CONFIG_OUT}) + +############################################################################### +# determine source and header files +############################################################################### +file(GLOB AVANGO_CORE_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + src/avango/*.cpp + src/avango/actions/*.cpp + src/avango/fields/*.cpp + src/avango/interface/*.cpp + src/avango/logging/*.cpp + src/avango/nodes/*.cpp + src/avango/streams/*.cpp + src/avango/support/*.cpp + src/avango/types/*.cpp + include/avango/*.h + include/avango/logging/*.h +) + +############################################################################### +# optional sources for distribution support +############################################################################### +IF (${AVANGO_DISTRIBUTION_SUPPORT}) + file(GLOB AVANGO_CORE_DISTRIBUTION_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + src/avango/network/*.cpp + src/avango/network/*.h + ) + IF (NOT ${AVANGO_ZMQ_DISTRIBUTION_SUPPORT}) + list (REMOVE_ITEM AVANGO_CORE_DISTRIBUTION_SRC + src/avango/network/NetNodeClient.cpp + src/avango/network/NetNodeClient.h + src/avango/network/NetNodeServer.cpp + src/avango/network/NetNodeServer.h + ) + ENDIF (NOT ${AVANGO_ZMQ_DISTRIBUTION_SUPPORT}) +ENDIF (${AVANGO_DISTRIBUTION_SUPPORT}) + +LINK_DIRECTORIES(${LIB_PATHS}) + +ADD_LIBRARY( avango_core SHARED + ${AVANGO_CORE_SRC} +) + +INCLUDE_DIRECTORIES( avango_core + ${INCLUDE_PATHS} + include + ../avango-unittest/include +) + +IF (NOT ${LIBRARIES} STREQUAL "") + TARGET_LINK_LIBRARIES( avango_core debug ${LIBRARIES} optimized ${LIBRARIES}) +ENDIF (NOT ${LIBRARIES} STREQUAL "") + +############################################################################### +# targets for unittesting +############################################################################### +IF (AVANGO_UNITTESTS) + # general tests + ADD_EXECUTABLE(unittest_mock_field_container "src/avango/nodes/tests/MockFieldContainer.cpp") + ADD_EXECUTABLE(unittest_abstract_node "src/avango/nodes/tests/TestAbstractNode.cpp") + ADD_EXECUTABLE(unittest_evaluation "src/avango/nodes/tests/TestEvaluation.cpp") + ADD_EXECUTABLE(unittest_evaluation_order "src/avango/nodes/tests/TestEvaluationOrder.cpp") + ADD_EXECUTABLE(unittest_field_connection "src/avango/nodes/tests/TestFieldConnectionChangeInNotify.cpp") + ADD_EXECUTABLE(unittest_nodes_field_container "src/avango/nodes/tests/TestFieldContainer.cpp") + ADD_EXECUTABLE(unittest_nodes "src/avango/nodes/tests/TestNodes.cpp") + ADD_EXECUTABLE(unittest_nodes_unref "src/avango/nodes/tests/TestUnref.cpp") + + #logging + ADD_EXECUTABLE(unittest_logging "src/avango/logging/tests/TestLogging.cpp") + + #interface + ADD_EXECUTABLE(unittest_application "src/avango/interface/tests/TestApplication.cpp") + ADD_EXECUTABLE(unittest_time_sensor "src/avango/interface/tests/TestTimeSensor.cpp") + + # type tests + ADD_EXECUTABLE(unittest_container_pool "src/avango/types/tests/TestContainerPool.cpp") + ADD_EXECUTABLE(unittest_libtype "src/avango/types/tests/TestLibType.cpp") + ADD_EXECUTABLE(unittest_type "src/avango/types/tests/TestType.cpp") + + # fields + ADD_EXECUTABLE(unittest_fields "src/avango/fields/tests/TestFields.cpp") + IF (AVANGO_DISTRIBUTION_SUPPORT) + ADD_EXECUTABLE(unittest_clone_fields "src/avango/fields/tests/TestCloneFields.cpp") + ADD_EXECUTABLE(unittest_field_const "src/avango/fields/tests/TestFieldConst.cpp") + ADD_EXECUTABLE(unittest_field_multipush "src/avango/fields/tests/TestFieldMultiPush.cpp") + ADD_EXECUTABLE(unittest_field_referencing "src/avango/fields/tests/TestFieldReferencing.cpp") + ADD_EXECUTABLE(unittest_field_type_conversion "src/avango/fields/tests/TestFieldTypeConversion.cpp") + ADD_EXECUTABLE(unittest_field_value_callbacks "src/avango/fields/tests/TestFieldValueCallbacks.cpp") + ADD_EXECUTABLE(unittest_multifields "src/avango/fields/tests/TestMultiFields.cpp") + # network + ADD_EXECUTABLE(unittest_net_lock "src/avango/network/tests/TestNetLock.cpp") + ADD_EXECUTABLE(unittest_net_node "src/avango/network/tests/TestNetNode.cpp") + ADD_EXECUTABLE(unittest_network "src/avango/network/tests/TestNetwork.cpp") + ENDIF (AVANGO_DISTRIBUTION_SUPPORT) + + TARGET_LINK_LIBRARIES( unittest_fields debug avango_core optimized avango_core) +ENDIF (AVANGO_UNITTESTS) \ No newline at end of file diff --git a/avango-core/include/avango/Action.h b/avango-core/include/avango/Action.h new file mode 100644 index 00000000..b2432165 --- /dev/null +++ b/avango-core/include/avango/Action.h @@ -0,0 +1,104 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_ACTION_H) +#define AV_ACTION_H + +/** + * \file + * \ingroup av + */ + +// includes, system + +// includes, project + +#include +#include + +namespace av +{ + + // types, exported (class, enum, struct, union, typedef) + + /** + * %Base class for all action classes. + * + * Action allows operations to be applied to nodes in hierarchies. + * Concrete actions usually re-implement apply() to add initialization + * code to the traversal and add per node functionality to traverse(). + * + * traverse() itself calls Base::doAction(*this) for node + * specific recursion. You should invoke the parent traverse() + * function in classes inherited from Action. + * + * \ingroup av + * + */ + class AV_DLL Action : public Base + { + + AV_BASE_DECLARE(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~Action(); + + public: + + /** + * Apply action to nodes. + * \param node Node to which the action applies + */ + virtual void apply(Link node); + + /** + * Node traversal function. + * \param node Node to which the action applies + */ + virtual void traverse(Link node); + + protected: + + /** + * Constructor. + * Made protected to prevent instantiation of Action objects. + */ + Action(); + + }; + + // variables, exported (extern) + + // functions, inlined (inline) + + // functions, exported (extern) + +} + +#endif // #if !defined(AV_ACTION_H) diff --git a/avango-core/include/avango/Application.h b/avango-core/include/avango/Application.h new file mode 100644 index 00000000..4f69b5bf --- /dev/null +++ b/avango-core/include/avango/Application.h @@ -0,0 +1,161 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// $Id + +#if !defined(AV_APPLICATION_H) +#define AV_APPLICATION_H + +#include +#include +#include + +#include + +#include "windows_specific.h" + +/** + * \file + * \ingroup av + */ + +namespace av +{ + + /** + * The Application class initializes the Avango runtime system and + * encapsulates the Avango main loop. + * + * There is exactly one Application object per application which can be + * accessed through the getInstance() function. + * + * \ingroup av + */ + //typedef Singleton + class AV_DLL Application /* : public Singleton*/ + { + //friend class Singleton; + + /** + * Constructor made private to prevent multiple instantiation. + */ + public: + + Application(); + /** + * Destructor made private to prevent deletion. + */ + ~Application(); + + /** + * Triggers Avango object evaluation once. + * TODO: Why is the pre and post evaluation signal needed? Does it make sense? As far as we know, it is only used in the NetMatrixTransform node. + */ + void evaluate(); + + /** + * Returns true if the main loop is running. + */ + bool running(); + + /** + * Starts the main loop + * Returns true if the main loop has not been running before. + */ + bool start(); + + /** + * Starts the main loop in a background thread. + * + * Note that Avango is not thread-safe in general. + * Nothing is done for synchronization at this point. + * Use this only if you know what you are doing. + */ + void startInBackground(); + + /** + * Stops the mainloop gracefully after current step. + * Returns true if the main loop has not been stopped already. + */ + bool stop(); + + /** + * Exits the application gracefully. + */ + void exit(bool realExit = true); + + typedef boost::signal VoidCallbackSignal; + typedef VoidCallbackSignal::slot_type VoidCallback; + typedef boost::signals::connection CallbackHandle; + + /** + * add a callback which is called before the evaluation of Avango FieldContainers + */ + CallbackHandle addPreEvaluationContainerCallback(const VoidCallback& callback); + + /** + * add a callback which is called after the evaluation of Avango FieldContainers + */ + CallbackHandle addPostEvaluationContainerCallback(const VoidCallback& callback); + + /** + * add a render callback which is called after each + * evaluation of Avango objects + */ + CallbackHandle addRenderCallback(const VoidCallback& callback); + + /** + * remove a callback + */ + static void removeCallback(const CallbackHandle& handle); + + private: + + void disconnectAllFields(); + void cleanExit(); + + // Some checks have to be done to allow exit and stop calls from inside evaluate + // These flags are used for this. + + bool mCleanExit; + bool mKeepRunning; + bool mRealExit; + bool mRunning; + + // why boost::thread::thread? boost::shared_ptr mThread; + boost::shared_ptr mThread; + VoidCallbackSignal mPreEvaluateContainerCallbackSignal; + VoidCallbackSignal mPostEvaluateContainerCallbackSignal; + VoidCallbackSignal mRenderCallbackSignal; + + }; + + typedef Singleton ApplicationInstance; + +} + +#endif // #if !defined(AV_APPLICATION_H) + +// $Id diff --git a/avango-core/include/avango/Assert.h b/avango-core/include/avango/Assert.h new file mode 100644 index 00000000..637f61a4 --- /dev/null +++ b/avango-core/include/avango/Assert.h @@ -0,0 +1,88 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_ASSERT_H) +#define AVANGO_ASSERT_H + +#include + +#if defined(_WIN32) +#include +#else +#define AV_DLL +#endif + +namespace av +{ + AV_DLL void assert_fail(const char* assertion, const char* file, + unsigned int line, const char* function); +} + +/** + * \file + * \ingroup av + */ + +/** + * \def AV_ASSERT(expr) + * + * Improved assert. It tries to start a debugger when an assertion occurs. + * The default debugger (gdb) can be overridden by setting the AV_DEBUGGER + * environment variable accordingly. + * + * \ingroup av + */ + +/** + * \def AV_ASSERT_FUNCTION + * + * Try to get a nicely formatted function name from the current context. + * AV_ASSERT_FUNCTION tries to use the default __ASSERT_FUNCTION from GLIBC. + * + * \ingroup av + */ + +#ifdef NDEBUG + +# define AV_ASSERT(expr) (static_cast(0)) + +#else // #ifdef NDEBUG + +# define AV_ASSERT(expr) \ + ((expr) \ + ? static_cast(0) \ + : (::av::assert_fail(#expr, __FILE__, __LINE__, AV_ASSERT_FUNCTION), \ + static_cast(0))) + +// use GLIBC __ASSERT_FUNCTION whenever possible +# if defined __ASSERT_FUNCTION +# define AV_ASSERT_FUNCTION __ASSERT_FUNCTION +# else +# define AV_ASSERT_FUNCTION ((const char *) 0) +# endif + +#endif // #ifdef NDEBUG + +#endif // #if !defined(AVANGO_ASSERT_H) diff --git a/avango-core/include/avango/Base.h b/avango-core/include/avango/Base.h new file mode 100644 index 00000000..1bd23735 --- /dev/null +++ b/avango-core/include/avango/Base.h @@ -0,0 +1,316 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_BASE_H) +#define AV_BASE_H + +/** + * \file + * \ingroup av + */ + +// includes, system + +// includes, project + +#include +#include +#include + +namespace av +{ + + class InputStream; + class OutputStream; + class Action; + class WriteAction; + + // types, exported (class, enum, struct, union, typedef) + + /** + * This class provides reference counting, type-safe casting and + * facilities for Action traversals and streaming. + * + * Base adds a public interface for streaming. An object can be + * written to or read from a stream using the member functions read() + * and write() or the provided global stream operators. + * + * Objects are automatically deleted when their reference count + * goes to zero. This can be override by setting the + * AVANGO_NO_DELETE_ON_UNREF environment variable. + * + * You cannot allocate instances of Base on the stack, but they can be + * created with new. They should be stored in Link smart pointers, + * so that they are automatically deleted when the reference count goes + * to zero. + * + * \ingroup av + * + */ + class AV_DLL Base : public Typed + { + + AV_TYPED_DECLARE_ABSTRACT(); + + public: + + /** + * Constructor + */ + Base(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~Base(); + + public: + + /** + * Increment the reference count. + */ + void reference(); + + /** + * Decrement the reference count. If the reference count becomes 0, + * the object is destroyed. This can be overriden by setting the + * AVANGO_NO_DELETE_ON_UNREF environment variable. + * + * Aborts if the reference count is already 0. + */ + void unreference(); + + /** + * Decrement the reference count, but do not delete object if the + * reference count becomes 0. Use with care. + * + * To delete the object later on, it first needs to be referenced, as + * otherwise the unreference will abort. + */ + void unreferenceWithoutDeletion(); + + /** + * Return the current reference count of the object. + */ + int referenceCount(); + + /** + * Sets a 'floating' reference. The floating reference ensures that an + * object is not deleted, even if its actual reference count decreases to + * zero. The next increment of the reference count will convert the + * floating reference to a normal one. + * + * This is mostly required during the 'birth' of an object. It helps to + * ensure that the object will actually survive. + */ + void setFloatingReference(); + + /** + * Try to find an inheritance path to the requested Type. + * + * Returns 0 if no such path exists. You can use the result to savely + * cast to the requested Type if not 0. + */ + Base* castTo(Type type); + + /** + * A static version of castTo(). + */ + static Base* castTo(Type type, Base* objectToCast); + + /** + * Overload this function to implement special behaviour on Action + * traverals. + * + * Beware: If you overload this function and want to preserve the + * behaviour of the parent class, you have to explicitly call + * parentClass::doAction() from within. + */ + virtual void doAction(Action& action); + + /** + * Overload this function to implement special behaviour on + * WriteAction traversals. + * + * Beware: If you overload this function and want to preserve + * the behaviour of the parent class, you have to explicitly call + * parentClass::doWriteAction() from within. + */ + virtual void doWriteAction(WriteAction& writeAction); + + /** + * Read the internal state of this object from the stream is. + * Must be overloaded, this implementation does nothing. + */ + virtual void read(InputStream& is); + + /** + * Write the internal state of this object to the stream os. + * Must be overloaded, this implementation does nothing. + */ + virtual void write(OutputStream& os); + + protected: + + /** + * Internally increment reference count. + * + * This virtual function implements part of the reference + * counting mechanism. + */ + virtual void refImpl(); + + /** + * Internally decrement reference count. + * + * This virtual function implements part of the reference + * counting mechanism. + */ + virtual void unrefImpl(); + + /** + * Internally decrement reference count. + * + * This virtual function implements part of the reference + * counting mechanism. + */ + virtual void unrefWithoutDeletionImpl(); + + /** + * Internally return reference count. + * + * This virtual function implements part of the reference + * counting mechanism. + */ + virtual int refCountImpl(); + + /** + * Sets a 'floating' reference. + * + * This virtual function implements part of the reference + * counting mechanism. + */ + virtual void setFloatingRefImpl(); + + private: + + int mRefCount; + bool mHasFloatingRef; + + void writeToBinaryStream(WriteAction& action); + void writeToASCIIStream(WriteAction& action); + + }; + + // variables, exported (extern) + + // functions, inlined (inline) + + // functions, exported (extern) + + /** + * Read the internal state of the object obj from the stream os. + */ + extern AV_DLL InputStream& operator>>(InputStream& is, Base* obj); + + /** + * Write the internal state of the object obj to the stream os. + */ + extern AV_DLL OutputStream& operator<<(OutputStream& os, Base* obj); + +} + +// subclassing macros + +/** + * This macro must be called in the definition of all concrete classes + * derived from av::Base. + * + * \ingroup av + */ +#define AV_BASE_DECLARE() \ + AV_TYPED_DECLARE() + +/** + * This macro must be called in the definition of all abstract classes + * derived from av::Base. + * + * \ingroup av + */ +#define AV_BASE_DECLARE_ABSTRACT() \ + AV_TYPED_DECLARE_ABSTRACT() + +/** + * This macro must be called at toplevel for all abstract classes + * derived from av::Base. + * + * \pre AV_BASE_DECLARE_ABSTRACT() must have been called prior to this. + * + * \ingroup av + */ +#define AV_BASE_DEFINE_ABSTRACT(thisClass) \ + AV_TYPED_DEFINE_ABSTRACT(thisClass) + +/** + * This macro must be called at toplevel for all concrete classes + * derived from av::Base. + * + * \pre AV_BASE_DECLARE() must have been called prior to this. + * + * \ingroup av + */ +#define AV_BASE_DEFINE(thisClass) \ + AV_TYPED_DEFINE(thisClass) + +/** + * This macro must be called in DerivedClass::initClass() for all + * abstract classes derived from av::Base. + * + * \pre AV_BASE_DECLARE_ABSTRACT() must have been called prior to this. + * \pre All parent classes must have been initialized. You can ensure this + * by calling ParentClass::initClass(). + * + * \ingroup av + */ +#define AV_BASE_INIT_ABSTRACT(parentClass, thisClass, isPublic) \ + AV_TYPED_INIT_ABSTRACT(parentClass, thisClass, isPublic) + +/** + * This macro must be called in DerivedClass::initClass() for all + * concrete classes derived from av::Base. + * + * \pre AV_BASE_DECLARE() must have been called prior to this. + * \pre All parent classes must have been initialized. You can ensure this + * by calling ParentClass::initClass(). + * + * \ingroup av + */ +#define AV_BASE_INIT(parentClass, thisClass, isPublic) \ + AV_TYPED_INIT(parentClass, thisClass, \ + new ::av::CreateA, isPublic) + +#endif // #if !defined(AV_BASE_H) diff --git a/avango-core/include/avango/Config.h b/avango-core/include/avango/Config.h new file mode 100644 index 00000000..70349e84 --- /dev/null +++ b/avango-core/include/avango/Config.h @@ -0,0 +1,63 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_CONFIG_H) +#define AVANGO_CONFIG_H + +/** + * \file + * \ingroup av + */ + +#if _AVANGO_DEBUG +#define AVANGO_DEBUG 1 +#else +#undef AVANGO_DEBUG +#endif + +#define AVANGO_LOG_LEVEL av::logging::WARN + +#if _AVANGO_DISTRIBUTION_SUPPORT +#define AVANGO_DISTRIBUTION_SUPPORT 1 +#else +#undef AVANGO_DISTRIBUTION_SUPPORT +#endif + +#if _AVANGO_ZMQ_DISTRIBUTION_SUPPORT +#define ZMQ_DISTRIBUTION_SUPPORT 1 +#else +#undef ZMQ_DISTRIBUTION_SUPPORT +#endif + +#if _AVANGO_PCL_SUPPORT +#define PCL_SUPPORT 1 +#else +#undef PCL_SUPPORT +#endif + +#define AVANGO_VERSION_MAJOR _AVANGO_VERSION_MAJOR +#define AVANGO_VERSION_MINOR _AVANGO_VERSION_MINOR +#define AVANGO_VERSION_MAINT _AVANGO_VERSION_MAINT + +#endif // #if !defined(AVANGO_CONFIG_H) + diff --git a/avango-core/include/avango/Config.h.in b/avango-core/include/avango/Config.h.in new file mode 100644 index 00000000..5651102d --- /dev/null +++ b/avango-core/include/avango/Config.h.in @@ -0,0 +1,63 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_CONFIG_H) +#define AVANGO_CONFIG_H + +/** + * \file + * \ingroup av + */ + +#if %(AVANGO_DEBUG)s +#define AVANGO_DEBUG 1 +#else +#undef AVANGO_DEBUG +#endif + +#define AVANGO_LOG_LEVEL av::logging::%(AVANGO_LOG_LEVEL)s + +#if %(AVANGO_DISTRIBUTION_SUPPORT)s +#define AVANGO_DISTRIBUTION_SUPPORT 1 +#else +#undef AVANGO_DISTRIBUTION_SUPPORT +#endif + +#if %(AVANGO_ZMQ_DISTRIBUTION_SUPPORT)s +#define ZMQ_DISTRIBUTION_SUPPORT 1 +#else +#undef ZMQ_DISTRIBUTION_SUPPORT +#endif + +#if %(AVANGO_PCL_SUPPORT)s +#define PCL_SUPPORT 1 +#else +#undef PCL_SUPPORT +#endif + +#define AVANGO_VERSION_MAJOR %(AVANGO_VERSION_MAJOR)s +#define AVANGO_VERSION_MINOR %(AVANGO_VERSION_MINOR)s +#define AVANGO_VERSION_MAINT %(AVANGO_VERSION_MAINT)s + +#endif // #if !defined(AVANGO_CONFIG_H) + diff --git a/avango-core/include/avango/ContainerPool.h b/avango-core/include/avango/ContainerPool.h new file mode 100644 index 00000000..d4b849ce --- /dev/null +++ b/avango-core/include/avango/ContainerPool.h @@ -0,0 +1,201 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_CONTAINERPOOL_H) +#define AVANGO_CONTAINERPOOL_H + +/** + * \file + * \ingroup av + */ + +#include +#include +#include +#include + +#include + +namespace av +{ + + /** + * All field containers are registered here. + * + * \ingroup av + */ + class AV_DLL ContainerPool + { + + public: + + typedef FieldContainer::IDType FieldContainerID; + + typedef std::map InstancePoolType; + typedef void (*NodeCreationCallback)(FieldContainer*, void*); + typedef void (*NodeDeletionCallback)(FieldContainer*, void*); + typedef void (*FieldConnectCallback)(Field*, void*); + typedef void (*FieldDisconnectCallback)(Field*, void*); + typedef void (*FieldHasChangedCallback)(Field*, void*); + + struct FieldHasChangedReg + { + FieldHasChangedReg(FieldHasChangedCallback c, Field* f, void* ud); + FieldHasChangedCallback mCb; + Field* mField; + void* mUserData; + }; + + typedef std::list > NodeCreationCallbacksType; + typedef std::list > NodeDeletionCallbacksType; + typedef std::list > FieldConnectCallbacksType; + typedef std::list > FieldDisconnectCallbacksType; + typedef std::list FieldHasChangedCallbacksType; + + static unsigned int getNumberOfContainers() {return sContainerPool.size();}; + + static const InstancePoolType& getContainerPool () {return sContainerPool;}; + static FieldContainerID registerInstance(FieldContainer*); + static void unregisterInstance(FieldContainer*); + + static void setNameForInstance(FieldContainer* fc, const std::string& name); + static void setNameForInstance(FieldContainer* fc, const char* name); + static void removeNameForInstance(FieldContainer* fc); + static FieldContainer* getInstanceByName(const std::string& name); + static std::string getNameByInstance(FieldContainer* fc); + static FieldContainer* getContainerById(FieldContainerID id); + + static void notifyConnect(Field* field); + static void notifyDisconnect(Field* field); + + static void notifyFieldHasChanged( Field* field); + static void notifyCreation(FieldContainer* fc); + static void notifyDeletion(FieldContainer* fc); + + class NodeCreationCallbackID + { + friend class ContainerPool; + + public: + NodeCreationCallbackID(); + + private: + NodeCreationCallbackID(NodeCreationCallbacksType::iterator); + NodeCreationCallbacksType::iterator mCallbackIter; + }; + + static NodeCreationCallbackID registerNodeCreationCallback(NodeCreationCallback, void*); + static void unregisterNodeCreationCallback(NodeCreationCallbackID); + + class NodeDeletionCallbackID + { + friend class ContainerPool; + + public: + NodeDeletionCallbackID(); + + private: + NodeDeletionCallbackID(NodeDeletionCallbacksType::iterator); + NodeDeletionCallbacksType::iterator mCallbackIter; + }; + + static NodeDeletionCallbackID registerNodeDeletionCallback(NodeDeletionCallback, void*); + static void unregisterNodeDeletionCallback(NodeDeletionCallbackID); + + class FieldConnectCallbackID + { + friend class ContainerPool; + + public: + FieldConnectCallbackID(); + + private: + FieldConnectCallbackID(FieldConnectCallbacksType::iterator); + FieldConnectCallbacksType::iterator mCallbackIter; + }; + + static FieldConnectCallbackID registerFieldConnectCallback(FieldConnectCallback, void*); + static void unregisterFieldConnectCallback(FieldConnectCallbackID); + + class FieldDisconnectCallbackID + { + friend class ContainerPool; + + public: + FieldDisconnectCallbackID(); + + private: + FieldDisconnectCallbackID(FieldDisconnectCallbacksType::iterator); + FieldDisconnectCallbacksType::iterator mCallbackIter; + }; + + static FieldDisconnectCallbackID registerFieldDisconnectCallback( + FieldDisconnectCallback, void*); + static void unregisterFieldDisconnectCallback(FieldDisconnectCallbackID); + + class FieldHasChangedCallbackID + { + friend class ContainerPool; + + public: + FieldHasChangedCallbackID(); + + private: + FieldHasChangedCallbackID(FieldHasChangedCallbacksType::iterator); + FieldHasChangedCallbacksType::iterator mCallbackIter; + }; + + static FieldHasChangedCallbackID registerFieldHasChangedCallback( + FieldHasChangedCallback, Field*, void*); + static void unregisterFieldHasChangedCallback(FieldHasChangedCallbackID); + + private: + static InstancePoolType sContainerPool; + static NodeCreationCallbacksType sCreationCallbacks; + static NodeDeletionCallbacksType sDeletionCallbacks; + static FieldConnectCallbacksType sConnectCallbacks; + static FieldDisconnectCallbacksType sDisconnectCallbacks; + static FieldHasChangedCallbacksType sFieldHasChangedCallbacks; + + typedef std::map NameToContainerMap; + typedef std::map ContainerToNameMap; + + static NameToContainerMap sNameContainerMap; + static ContainerToNameMap sContainerNameMap; + + // declared but never defined + ContainerPool(); + ContainerPool(const ContainerPool&); + ~ContainerPool(); + const ContainerPool& operator=(const ContainerPool&); + + // Holds the last assigned id value for a FieldContainer entering the pool. + static FieldContainerID sLastId; + + }; + +} // namespace av + +#endif diff --git a/avango-core/include/avango/Create.h b/avango-core/include/avango/Create.h new file mode 100644 index 00000000..a943ceef --- /dev/null +++ b/avango-core/include/avango/Create.h @@ -0,0 +1,113 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_CREATE_H) +#define AV_CREATE_H + +/** + * \file + * \ingroup av + */ + +// includes, system + +// includes, project + +#include "windows_specific.h" + +namespace av +{ + + class Typed; + + // types, exported (class, enum, struct, union, typedef) + + /** + * An abstract interface for creating instances of Typed derived types. + * + * Create is a minimal factory-like interface for dynamically creating + * instances of types. The types that can be created are restricted to + * Typed derived types. Create itself cannot be used in any useful way, + * it is rather intended to be used internally by Type to store a + * generic pointer of a type's factory w/o actually knowing that type. + * + * \ingroup av + */ + class AV_DLL Create + { + + public: + + /** + * Destructor + */ + virtual ~Create(); + + /** + * A placeholder for the actual allocator function of a Typed derived + * type. + */ + virtual av::Typed* makeInstance() const = 0; + + }; + + /** + * CreateA implements the actual mechanism for creating instances of + * Typed derived types as declared in Create. + * + * CreateA is a minimal factory-like interface for dynamically + * creating instances of types. It is implemented as a template for + * compiler automated code generation. + * + * \ingroup av + */ + template + class CreateA : public Create + { + + public: + + /** + * Implements the actual allocation of a Typed derived type. + * + * \return A pointer to the newly created object + * \note The return value may be 0 + */ + virtual av::Typed* makeInstance() const + { + return new T; + } + + }; + + // variables, exported (extern) + + // functions, inlined (inline) + + // functions, exported (extern) + +} + +#endif // #if !defined(AV_CREATE_H) diff --git a/avango-core/include/avango/Distributed.h b/avango-core/include/avango/Distributed.h new file mode 100644 index 00000000..6b41bc3c --- /dev/null +++ b/avango-core/include/avango/Distributed.h @@ -0,0 +1,155 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_DISTRIBUTED_H) +#define AVANGO_DISTRIBUTED_H + +/** + * \file + * \ingroup av + */ + +#ifdef __GNUC__ // GNU C++ stores TR1 headers differently +#include +#else +#include +#endif + +#include +#include +#include + +namespace av +{ + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + + class NetID; + class NetInfo; + class Msg; + class NetNode; + +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) + + /** + * The Distributed class is the base class for all classes that can be distributed. + * It provides a simple public interface to some of the internals of the distribution. + * Although, normally the application programmer should not need to be concerned with such + * details. + * + * \ingroup av + * + */ + class AV_DLL Distributed : public Base + { + + AV_BASE_DECLARE_ABSTRACT(); + + public: + + /** + * Constructor + */ + Distributed(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~Distributed(); + + /** + * Returns \c true if this object has been created by the calling process. + * If this object is a replicated copy created by some other process, \c false + * is returned. + */ + bool isOwned() const; + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + + public: + + /** + * Returns \c true if this node is distributed. + */ + bool isDistributed() const; + + /** + * Returns the distribution group wide unique identifier for this object. + * If the this object is not distributed NetID::NullID is returned. + */ + const NetID& netID() const; + + /** + * Returns the network wide unique identifier for the process which created this object. + */ + const std::string& netCreator() const; + + /** + * Returns the NetNode of this instance. + */ + const NetNode* netNode() const; + + /** + * Returns the NetNode of this instance. + */ + NetNode* netNode(); + + /** + * Write to a net msg + */ + virtual void push(Msg& netMsg) = 0; + + /** + * Read from a net msg + */ + virtual void pop(Msg& netMsg) = 0; + + protected: + + friend class NetNode; + void setNetInfo(NetInfo* netInfo); + NetInfo* getNetInfo(); + + // notify the network of a local change + void notifyLocalChange(); + + // client code can do something here + virtual void becomingDistributed(); + virtual void becomingUndistributed(); + + private: + + NetInfo* mNetInfo; + +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) + + }; + + typedef std::tr1::unordered_set, AnyLink::Hasher, std::equal_to > DistributedSet; +} + +#endif // #if !defined(AVANGO_DISTRIBUTED_H) diff --git a/avango-core/include/avango/Doxygen.h b/avango-core/include/avango/Doxygen.h new file mode 100644 index 00000000..52c8ff58 --- /dev/null +++ b/avango-core/include/avango/Doxygen.h @@ -0,0 +1,44 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_DOXYGEN_H) +#define AVANGO_DOXYGEN_H + +/** + * \defgroup av AVANGO Core Library + */ + +/** + * \file + * \ingroup av + */ + +/** + * \namespace av + * AVANGO Core Library + * + * \ingroup av + */ + +#endif // #if !defined(AVANGO_DOXYGEN_H) + diff --git a/avango-core/include/avango/Field.h b/avango-core/include/avango/Field.h new file mode 100644 index 00000000..f8126201 --- /dev/null +++ b/avango-core/include/avango/Field.h @@ -0,0 +1,354 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_FIELD_H) +#define AVANGO_FIELD_H + +#include +#include +#include +#include + +#include +#include + +namespace av +{ + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + class Msg; +#endif + + class Create; + class FieldContainer; + class InputStream; + class OutputStream; + + /** + * Base class for all field types. + * Fields provide a generic scripting and streaming interface for + * accessing object state attributes. + * + * \ingroup av + */ + class AV_DLL Field : public Typed + { + + friend class FieldContainer; + + AV_TYPED_DECLARE_ABSTRACT(); + + public: + + class Event + { + friend class Field; + + public: + + /** + * Destructor + */ + virtual ~Event() {} + + /** + * The originating field of the event. + * + * The field gets invalid when its container is destroyed. + * So, you should reference the container if you are planning to hold + * the field or a copy of the event after the callback has returned. + * You can do this by storing the container in a Link (preferred) or + * by calling reference/dereference explicitly. + */ + const Field* getField() const { return mField; } + + protected: + Event(const Field *field) : mField(field) {} + + private: + const Field *mField; + }; + + enum FieldChangeSource + { + script, + connection, + tune, + tune_n, + untune, + activate, + deactivate, + apply, + unapply, + net, + internal + }; + + typedef std::set FieldPtrSet; + typedef std::vector FieldPtrVec; + + Field(); + virtual ~Field(); + + /** + * Returns a pointer to the container this field is contained in. + */ + FieldContainer* getContainer() const; + + /** + * Returns \c true if the field is bound to a field container. + */ + bool isBound() const; + + /** + * Returns the index of this field. The index can be used on FieldContainer methods + * (e.g. FieldContainer::getField()) + */ + unsigned int getIndex() const; + + /** + * Returns the name of this field. + */ + const std::string& getName() const; + + /** + * Connects \c field to this field. A field can have multiple connections + * \em from other fields if in multi-input mode (see setMultiInput()) and can be connected + * \em to any number of fields. + * + * A field connected from another field has the same value as that field . Exceptions: + * - notify (see enableNotify()) for the source field had been disabled when its value has + * changed the last time + * - the source field's value is only propagated once per frame if single-pushed + * (see setMultiPush()) + * + * The dependent flag is used to signal that the connection is used to express a dependency + * of the FieldContainer this field belongs to on the FieldContainer field that field belongs + * to. + */ + void connectFrom(Field* field, bool dependent = true); + + /** + * Remove the connection from all connected fields. + */ + void disconnect(); + + /** + * Remove the connection from a specific field. + * Useful if the field is multi-input enabled (see setMultiInput()). + */ + void disconnectFrom(Field* from); + + /** + * Returns a const reference to the set of field auditors. + */ + const FieldPtrSet& getAuditors() const; + + /** + * Remove all connections to other fields. + */ + void disconnectAuditors(); + + /** + * Returns the field with index \c index (default: 0) this field is connected from. + * If there is no connection with this index the null pointer is returned. + */ + Field* getConnectedField(unsigned int index = 0); + + /** + * Returns the number of fields which are connected to this field. + */ + unsigned int getNumberOfConnectedFields() const; + + /** + * Enable or disable dependency on this field. If enabled, the field container is dependent + * on other field container, which have field connected to this field. + */ + void enableDependency(bool on); + + /** + * Returns \c true if dependency is enabled for this field. + */ + bool dependencyEnabled(); + + /** + * Enable or disable notification on this field. If enabled, changes to fields or calls to + * touch() are propagated to all connected fields. + */ + void enableNotify(bool on); + + /** + * Returns \c true if notification is enabled for this field. + */ + bool notifyEnabled(); + + /** + * Simulates a change to the fields value with respect to the notification mechanism. + */ + void touch(); + + /** + * Bind field with name \c name to \c container. + * This function shouldn't be invoked directly. It is called by the AV_FC_INIT macros. + */ + void bind(FieldContainer* container, const std::string& name, bool owned); + + /** + * Unset the current container of the field. + * This function shouldn't be invoked directly. It is called by the FieldContainer::removeDynamicField function. + */ + void unbind(); + + /** + * Sets the field to a type dependent default value. + */ + virtual void clear(); + + /** + * Reads the field from an InputStream + */ + virtual void read(InputStream& is) = 0; + + /** + * Writes the field to an OutputStream + */ + virtual void write(OutputStream& os) = 0; + + /** + * Reads field connection info from an InputStream + */ + void readConnection(InputStream& is); + + /** + * Writes field connection info to an OutputStream + */ + void writeConnection(OutputStream& os); + + /** + * Dont't ever write this field out. + */ + void dontWrite(bool on); + + /** + * Is this a writeable field? + */ + bool isWritable() const; + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + virtual void push(Msg&) = 0; + virtual void pop(Msg&) = 0; +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) + + void dontDistribute(bool on); + bool isDistributable() const; + + void needsDistribution(bool on); + bool needsDistribution() const; + + bool isMultiPush() const; + void setMultiPush(bool); + + bool isMultiInput() const; + void setMultiInput(bool); + + bool isOwned() const; + + FieldChangeSource getFieldChangeSource() const; + void setFieldChangeSource(FieldChangeSource src); + + /** + * Create a new instance of same field type and same value. + * This type is not added to any container or event handler. + */ + virtual Field* clone(void) const = 0; + + /** + * Call evaluate on dependent field containers. + */ + virtual void evaluateDependencies(void); + + protected: + + /** + * Fields are always wrapped up in a container. + */ + void setContainer(FieldContainer* c, unsigned int i, bool owned); + + static Type registerType(const std::string& classname, + const std::string& parentname, + Create* creator); + + void fieldChanged(bool from_net = false, Field* triggered_from = 0); + void reset(); + + virtual void notify(Field* triggered_from = 0); + + void addAuditor(Field* field); + void removeAuditor(Field* field); + + virtual void pullValue(Field* fromField) = 0; + + FieldContainer* mContainer; + + private: + + // disable copy construction + Field(const Field&); + + FieldPtrSet mAuditors; + + typedef std::pair FieldConnection; + typedef std::list InputFieldsList; + InputFieldsList mConnectedFrom; + + struct { + bool touched :1; // has the field been touched? + bool dependencyEnabled :1; // dependency on field? + bool notifyEnabled :1; // notify field changes? + bool hasNotified :1; // has the field been notified? + bool dontWrite :1; // never write this field to a stream + bool dontDistribute :1; // never distribute this field over the net + bool needsDistribution :1; // does the field need distribution + bool multiPush :1; // allow/disallow multiple value push to field auditors per frame + bool multiInput :1; // allow/disallow multiple inputs to field + bool owned :1; // is field owned by container? + } mFlags; + + unsigned int mIndex; + bool mIsNotifying; + FieldChangeSource mSrc; + + }; + + // streaming support + extern AV_DLL InputStream& operator>>(InputStream& is, Field* field); + extern AV_DLL OutputStream& operator<<(OutputStream& os, const Field* field); + +} // namespace av + +#define AV_FIELD_DEFINE(thisClass) \ + template<> av::Type thisClass::sClassTypeId = av::Type::badType(); + +#endif // #if !defined(AVANGO_FIELD_H) diff --git a/avango-core/include/avango/FieldContainer.h b/avango-core/include/avango/FieldContainer.h new file mode 100644 index 00000000..e170c230 --- /dev/null +++ b/avango-core/include/avango/FieldContainer.h @@ -0,0 +1,358 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_FIELDCONTAINER_H) +#define AVANGO_FIELDCONTAINER_H + +/** + * \file + * \ingroup av + */ + +#include +#include +#include + +#ifdef __GNUC__ // GNU C++ stores TR1 headers differently +#include +#else +#include +#endif + +namespace av +{ + class InputStream; + class OutputStream; + class Field; + class FieldRef; + + /** + * The FieldContainer class is the base class for all classes which + * contain fields (see Field) to encapsulate object attributes. + * It provides methods to query number, name, type and value of any field + * it contains. + * + * It provides a complex macro package which should be used by + * derived classes in order for runtime typing, reference counting, + * field declaration and inheritance to work. + * + * \ingroup av + */ + class AV_DLL FieldContainer : public Distributed + { + friend class Field; + + AV_BASE_DECLARE_ABSTRACT(); + + public: + + typedef long int IDType; + + /** + * Constructor + */ + FieldContainer(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~FieldContainer(); + + public: + + /** + * Name of the field container. + */ + SFString Name; + + /** + * Returns the number of fields in this field container. + */ + unsigned int getNumFields(); + + /** + * Returns the number of fields in this field container which will be written to streams. + */ + unsigned int getNumWriteableFields(); + + /** + * Disconnects all Fields contained in this FieldContainer. + */ + void disconnectAllFields(); + + /** + * Dynamically adds a field by type name to this field container. + * Adding a new field with a name of an already existing field is prohibited, and + * is checked with an assertion. + */ + virtual void addDynamicField(const std::string& typeName, const std::string& fieldName); + + /** + * Dynamically adds a copy of a field to this field container. + * Adding a new field with a name of an already existing field is prohibited, and + * is checked with an assertion. + */ + virtual void addDynamicField(Field* field, const std::string& fieldName); + + /** + * Remove a field from the field container. + * CAUTION: If you use this functionality + * 1) The avango distribution will not work correctly. + * 2) The id of the fields will change. Therefore code which stores and resembles + * the id of fields may and most propably will not work correctly. + */ + virtual void removeDynamicField(const std::string& fieldName); + + /** + * Returns true if there is a field named \e name. + */ + virtual bool hasField(const std::string& name); + + /** + * Returns a pointer to the field with index \e index. + * If there is no such field, a null pointer is returned. + */ + virtual Field* getField(unsigned int index); + + /** + * Returns a pointer to the field named \e name. + * If there is no such field, a null pointer is returned. + */ + virtual Field* getField(const std::string& name); + + /** + * Returns the name of the field with index \e index. + * If there is no such field, an empty string is returned. + */ + virtual const std::string& getFieldName(unsigned int index); + + /** + * Returns a vector of pointers to all fields in this container. + */ + virtual std::vector& getFields(); + + /** + * Returns the identifier. The return value is unique for this + * container for the currently running instance of Avango. + */ + IDType getId() const; + + /** + * Returns a fp_field_ref object that identifies a fields as field container + * pointer and field index. + */ + virtual bool getFieldRef(const std::string& name, FieldRef& fr); + + /** + * Mark this field container as touched. This has the same effect + * as if one of the fields had been touched. + */ + virtual void touch(bool from_net = false); + + /** + * Enable or disable notification on this node. If disabled, changes to + * fields or calls to touch() are not propagated to connected fields. + * This calls enableNotify on all fields. + */ + void enableNotify(bool on); + + /** Enable or disable scheduling on this node. If enabled, the node can be + * scheduled to be evaluated automatically. + */ + void allowScheduling(bool on); + + /** + * Set/unset an field-container to be evaluated every frame. + */ + void alwaysEvaluate(bool on); + + /** + * Evaluates another FieldContainer, if own evaluation depends on it, + * but there is no field connection to it. + * May only be called from evaluate or evaluteLocalSideEffect. + */ + void evaluateDependency(FieldContainer& dependency); + + /** + * Starts evaluation of all field containers. + */ + static void evaluateAllContainers(); + + /** + * Remove all containers from evaluation schedule. + * This function is primarily useful for cleanup at application exit + * and should not be called during normal operation. + */ + static void unscheduleEvaluationForAllContainers(); + + /** + * Get the number of FieldContainers which need to be evaluated + */ + static unsigned int getNumberOfContainersToEvaluate(); + + /** + * Get time of last change. + */ + double lastChange() const; + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + virtual void push(Msg&); + virtual void pop(Msg&); +#endif + + /** + * Read container representation from InputStream. + */ + virtual void read(InputStream& is); + + /** + * Write container representation to OutputStream. + */ + virtual void write(OutputStream& os); + + protected: + + /** + * Name adaptor field getter callback + */ + virtual void getNameCB(const av::SFString::GetValueEvent& event); + + /** + * Name adaptor field setter callback + */ + virtual void setNameCB(const av::SFString::SetValueEvent& event); + + /** + * Schedule this field container for evaluation (if needed). + */ + void scheduleForEvaluation(); + + /** + * Time of last change (used for synchronisation with graph display). + */ + double mLastChange; + + // you may overload these, if you use this as a base class + + /** + * This function is called whenever one of the fields has been changed. You want to + * overload this function, if you want your node to respond to field changes in a + * non standard way. evaluate() is called only once per simulation frame, even + * if multiple fields have been changed. + */ + virtual void evaluate(); + virtual void evaluateLocalSideEffect(); + + /** + * This function is called immediately after \e field has been changed. In a distributed + * setup you must not set or touch any other fields on this from within this function. + * This can savely be done in the evaluate() callback. + */ + virtual void fieldHasChanged(const Field& field); + virtual void fieldHasChangedLocalSideEffect(const Field& field); + + /** + * Returns \c true if a field of this container has changed in this frame. + */ + bool needsEvaluation() const; + + void callEvaluate(); + void fieldChanged(const Field& field, bool from_net = false); + + struct + { + bool mNeedsEvaluation:1; + bool mIsInEvaluationList:1; + bool mFieldsCalculated:1; + bool mAlwaysEvaluate:1; + bool mIsEvaluating:1; + bool mAllowScheduling:1; + } mFlags; + + private: + + typedef std::vector FieldPtrVec; + FieldPtrVec mFieldPtrs; // for fast lookup in getFields, do not use directly ! + + struct FieldInfo + { + FieldInfo() : mField(0) {} + Field* mField; + std::string mName; + }; + + typedef std::vector FieldInfos; + FieldInfos mFields; + + typedef std::tr1::unordered_map FieldsIndex; + FieldsIndex mFieldsIndex; + + FieldInfo* getFieldInfo(const std::string& name); + FieldInfo* getFieldInfo(unsigned int index); + + unsigned int addField(Field* field, const std::string& fieldName); + void removeField(unsigned int index); + IDType mId; + + unsigned int mEvaluateId; + static unsigned int sEvaluateId; + + }; + +#ifdef AV_INSTANTIATE_FIELD_TEMPLATES + template class AV_DLL SingleField >; + template class AV_DLL MultiField >; +#endif + + typedef SingleField > SFContainer; + typedef MultiField > MFContainer; + +} + +#define AV_FC_DECLARE() \ + AV_BASE_DECLARE() + +#define AV_FC_DECLARE_ABSTRACT() \ + AV_BASE_DECLARE_ABSTRACT() + +#define AV_FC_DEFINE_ABSTRACT(thisClass) \ + AV_BASE_DEFINE_ABSTRACT(thisClass) + +#define AV_FC_DEFINE(thisClass) \ + AV_BASE_DEFINE(thisClass) + +#define AV_FC_INIT_ABSTRACT(parentClass, thisClass, isPublic) \ + AV_BASE_INIT_ABSTRACT(parentClass, thisClass, isPublic) + +#define AV_FC_INIT(parentClass, thisClass, isPublic) \ + AV_BASE_INIT(parentClass, thisClass, isPublic) + +#define AV_FC_ADD_FIELD(fieldName, initialValue) \ + fieldName.bind(this, #fieldName, false, initialValue) + +#define AV_FC_ADD_ADAPTOR_FIELD(fieldName, getcb, setcb) \ + fieldName.bind(this, #fieldName, false, getcb, setcb) + +#endif // #if !defined(AVANGO_FIELDCONTAINER_H) diff --git a/avango-core/include/avango/FieldContainerHelper.h b/avango-core/include/avango/FieldContainerHelper.h new file mode 100644 index 00000000..b6cd2c6a --- /dev/null +++ b/avango-core/include/avango/FieldContainerHelper.h @@ -0,0 +1,48 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_FIELDCONTAINERHELPER_H) +#define AVANGO_FIELDCONTAINERHELPER_H + +/** + * \file + * \ingroup av + */ + +#include + +namespace av +{ + /** + * Helper function to disconnect all field connections from and to + * the given FieldContainer, and to clear all field values. + * Useful to avoid reference loops. + * + * \ingroup av + */ + AV_DLL void disconnectAndClearAllFields(FieldContainer* fieldContainer); +} + +#endif diff --git a/avango-core/include/avango/FieldRef.h b/avango-core/include/avango/FieldRef.h new file mode 100644 index 00000000..72db0d6e --- /dev/null +++ b/avango-core/include/avango/FieldRef.h @@ -0,0 +1,63 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_FIELDREF_H) +#define AVANGO_FIELDREF_H + +/** + * \file + * \ingroup av + */ + +#include + +namespace av +{ + class FieldContainer; + class Field; + + class AV_DLL FieldRef + { + public: + + FieldRef(); + FieldRef(const FieldRef&); + FieldRef(Field*); + ~FieldRef(); + + const FieldRef& operator=(const FieldRef&); + + Field* getField(); + + Link mFC; // field container + unsigned int mFi; // field index + }; +} + +#endif + + + + diff --git a/avango-core/include/avango/Init.h b/avango-core/include/avango/Init.h new file mode 100644 index 00000000..2bf41015 --- /dev/null +++ b/avango-core/include/avango/Init.h @@ -0,0 +1,52 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_INIT_H) +#define AVANGO_INIT_H + +/** + * \file + * \ingroup av_osg + */ + +#include + +namespace av +{ + + /** + * Initializes the Avango Core library. + * Usage: \code av::Init::initClass(); \endcode + * + * \ingroup av + */ + class Init + { + AV_TYPED_DECLARE_ABSTRACT(); + }; + +} + +#endif diff --git a/avango-core/include/avango/InputStream.h b/avango-core/include/avango/InputStream.h new file mode 100644 index 00000000..f5082d41 --- /dev/null +++ b/avango-core/include/avango/InputStream.h @@ -0,0 +1,155 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_INPUTSTREAM_H) +#define AV_INPUTSTREAM_H + +/** + * \file + * \ingroup av + */ + +#include "windows_specific.h" + +#if defined(_MSC_VER) + #include "stdint_replacement.h" +#else + #include +#endif // _MSC_VER + +#include +#include +#include + + +namespace av +{ + + class Reader; + + /** + * Class for reading Avango Objects from a stream. This is used + * for persistence and network distribution. + * + * \ingroup av + */ + + class AV_DLL InputStream : public std::istream + { + + public: + + /** + * Constructor + */ + InputStream(); + + /** + * Construct an InputStream from an existing istream + */ + InputStream(std::istream& is); + + /** + * Construct an InputStream from an existing streambuf + */ + InputStream(std::streambuf* sb); + + /** + * Assign an istream to an InputStream + */ + InputStream& operator=(std::istream& is); + + /** + * Assign a streambuf to an InputStream + */ + InputStream& operator=(std::streambuf* sb); + + /** + * Switch for enabling binary mode + */ + void enableBinary(bool on); + + /** + * Return \c true if the InputStream is in binary mode + */ + bool isBinaryEnabled() const; + + /** + * Set Reader for this stream. + */ + void setReader(Reader* reader); + + /** + * Get Reader for this Stream + */ + Reader* getReader(); + + private: + + bool mBinary; + Reader* mReader; + + }; + + // basic types + + AV_DLL InputStream& operator>>(InputStream& is, int16_t& value); + AV_DLL InputStream& operator>>(InputStream& is, uint16_t& value); + AV_DLL InputStream& operator>>(InputStream& is, int32_t& value); + AV_DLL InputStream& operator>>(InputStream& is, uint32_t& value); + AV_DLL InputStream& operator>>(InputStream& is, int64_t& value); + AV_DLL InputStream& operator>>(InputStream& is, uint64_t& value); + AV_DLL InputStream& operator>>(InputStream& is, float& value); + AV_DLL InputStream& operator>>(InputStream& is, double& value); + AV_DLL InputStream& operator>>(InputStream& is, bool& value); + AV_DLL InputStream& operator>>(InputStream& is, std::string& value); + + template InputStream& + operator>>(InputStream& is, std::pair& value) + { + return is >> value.first >> value.second; + } + + template InputStream& operator>>(InputStream& is, std::vector& value) + { + size_t count; + + is >> count; + + while (count) { + T tmp; + + is >> tmp; + value.push_back(tmp); + + --count; + } + + return is; + } + +} + +#endif // #if !defined(AV_INPUTSTREAM_H) diff --git a/avango-core/include/avango/Link.h b/avango-core/include/avango/Link.h new file mode 100644 index 00000000..caf68d6a --- /dev/null +++ b/avango-core/include/avango/Link.h @@ -0,0 +1,336 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_LINK_H) +#define AV_LINK_H + +/** + * \file + * \ingroup av + */ + +// includes, system + +#include + +// includes, project + +#include +#include +#include + + +namespace av +{ + + class InputStream; + class OutputStream; + + + // types, exported (class, enum, struct, union, typedef) + + /** + * Abstract base class for Link<> template class. All specializations of + * Link<> can be accessed through this interface. + * + * \ingroup av + */ + class AV_DLL AnyLink + { + + protected: + + static av::logging::Logger& logger; + + public: + + /** + * Hash Functor for using AnyLink in hash_map. + */ + class Hasher + { + public: + size_t operator()(const AnyLink& link) const + { + typedef size_t cast_destination_t; + return reinterpret_cast(link.getBasePtr())>>3; + } + }; + + /** + * Returns \c false if this is the \c null link. + */ + bool isValid() const; + + /** + * Makes this this the \c null link. + */ + void clear(); + + /** + * Returns the pointer contained in this link as a Base pointer. + * If the link is not valid, \c null is returned. + */ + Base* getBasePtr() const; + + /** + * Sets the pointer contained in this link. The argument is type + * checked against the concrete instance of Link<> this method is + * called on. If the type check succeeds, \c true is returned and the + * pointer is set, otherwise \c false is returned and no action is + * taken. + */ + bool setBasePtr(Base*); + + protected: + + AnyLink(Base* base, Type typeId); + virtual ~AnyLink(); + + Base* mBasePtr; + Type mTypeId; + + }; + + /** + * Compare two AnyLink for equality by comparing the contained + * pointer values. + * + * \ingroup av + */ + AV_DLL bool operator==(const AnyLink&, const AnyLink&); + + /** + * Compare two AnyLink for inequality by comparing the contained + * pointer values. + * + * \ingroup av + */ + AV_DLL bool operator!=(const AnyLink&, const AnyLink&); + + /** + * Compare two AnyLink by cardinality by comparing the contained pointer + * values. This is most useful in/for sorted STL containers. + * + * \ingroup av + */ + AV_DLL bool operator<(const AnyLink&, const AnyLink&); + + /** + * A typed smart pointer class. The Link class template makes the use + * of smart pointers typesafe with respect to the C++ compiler. T + * must be a class which is derived from Base. + * + * \ingroup av + */ + template + class Link : public AnyLink + { + + private: + + /** + * Be sure that T provides reference(). + * \see http://www.gotw.ca/gotw/071.htm + */ + bool validateRequirements() const + { + void(T::*test)() = &T::reference; + + if (test) + ; + + return true; + } + + public: + + /** + * Constructs a new, empty typed link. + */ + Link() : + AnyLink(0, T::getClassTypeId()) + {} + + /** + * Copy construct a new link. + */ + Link(const Link& link) + : AnyLink(link.getBasePtr(), T::getClassTypeId()) + {} + + /** + * Copy construct a new link from a compatible type. + */ + template + Link(const Link& link) + : AnyLink(convertToBase(link.getPtr()), T::getClassTypeId()) + {} + + + /** + * Constructs a new typed link to the object pointed to by \c ptr. + */ + Link(T* ptr) + : AnyLink(ptr, T::getClassTypeId()) + {} + + + /** + * Assign a link. This will increment the reference count of the + * referenced object. + */ + const Link& operator=(const Link& link) + { + if (this != &link) { + setBasePtr(link.getPtr()); + } + + return *this; + } + + + /** + * Dereferences a link like the standard '->' operator does on a + * normal pointer. If the link is empty or not valid an exeption + * would be thrown, if the dumb SGI C++ compiler would + * support exeption handling. For now an assertion is raised, i.e. + * the program is terminated. + * + * \todo Throw exception on empty link dereference. + * + */ + T* operator->() const + { + AV_ASSERT(mBasePtr); + return getPtr(); + } + + /** + * Returns a reference to the linked object. If the link is empty or + * not valid an assertion is raised, ie. the program is terminated. + * + * \todo Throw exception on empty link dereference. + * + */ + T& operator*() const + { + AV_ASSERT(mBasePtr); + return *getPtr(); + } + + /** + * Returns a pointer to the linked object. If the link is not valid, + * \c null is returned. + */ + T* getPtr() const + { + return static_cast(mBasePtr); + } + + /** + * Get a reference to the empty link. + */ + static const Link& empty() + { + return sEmptyLink; + } + + private: + Base* convertToBase(T* ptr) const { return ptr; } + static const Link& sEmptyLink; + }; + + // variables, exported (extern) + + // functions, inlined (inline) + + // functions, exported (extern) + + template + const Link& Link::sEmptyLink = Link(); + + /** + * Returns \c true if the lhs link points to the same object as the + * rhs link. + * + * \ingroup av + */ + template bool + operator==(const Link& lhs, const Link& rhs) + { + return lhs.getPtr() == rhs.getPtr(); + } + + /** + * Returns \c true if the lhs link does not point to the same object as + * the rhs link. + * + * \ingroup av + */ + template bool + operator!=(const Link& a, const Link& b) + { + return !(a == b); + } + + /** + * Returns \c true if the lhs link is 'less' than the rhs link. + * In fact, the absolute memory adresses of the linked objects are + * compared. + * + * \ingroup av + */ + template bool + operator<(const Link& lhs, const Link& rhs) + { + return lhs.getPtr() < rhs.getPtr(); + } + + /** + * Specialization for boost::mem_fn support. + * Together with boost::bind (which implicitly uses boost::mem_fn) you + * can iterate over a container of Links, e.g: + * + * \code + * void f(std::list >& objects) { + * for_each(objects.begin(), objects.end(), + * boost::bind(&Object::touch, _1)); + * } + * \endcode + * + * \ingroup av + */ + template T* get_pointer(const Link& link) + { + return link.getPtr(); + } + + AV_DLL InputStream& operator>>(InputStream& is, AnyLink& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const AnyLink& value); + +} + +#endif // #if !defined(AV_LINK_H) diff --git a/avango-core/include/avango/Logger.h b/avango-core/include/avango/Logger.h new file mode 100644 index 00000000..cc2a531f --- /dev/null +++ b/avango-core/include/avango/Logger.h @@ -0,0 +1,31 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGER_H) +#define AVANGO_LOGGER_H + +#include + +#endif // #if !defined(AVANGO_LOGGER_H) diff --git a/avango-core/include/avango/MaestroEID.h b/avango-core/include/avango/MaestroEID.h new file mode 100644 index 00000000..a031f61e --- /dev/null +++ b/avango-core/include/avango/MaestroEID.h @@ -0,0 +1,135 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_MAESTROEID_H) +#define AVANGO_MAESTROEID_H + +#include +#include +#include +#include + +#ifdef __GNUC__ // GNU C++ stores TR1 headers differently +#include +#include +#include +#else +#include +#include +#include +#endif + +#include + +namespace av +{ + + /** + * We need to add a few things to Maestro_EndpID for the STL. + */ + class MaestroEID : public Maestro_EndpID + { + + public: + + // for the STL hash containers + class Hasher + { + public: + size_t operator() (const MaestroEID& eid) const; + private: + std::tr1::hash mHasher; + }; + + MaestroEID(Maestro_ErrorHandler* error_handler = 0); + MaestroEID(hot_endpt_t ep, Maestro_ErrorHandler* error_handler = 0); + MaestroEID(const MaestroEID& eid); + MaestroEID(const Maestro_EndpID& eid); + + // support sorted STL container + bool operator<(const MaestroEID &eid) const; + bool operator==(const MaestroEID &eid) const; + bool operator!=(const MaestroEID &eid) const; + + // assignment + const MaestroEID& operator=(const MaestroEID& eid); + const MaestroEID& operator=(const Maestro_EndpID& eid); + + // get the C string + const char* c_str() const; + + friend Maestro_Message& operator<<(Maestro_Message &msg, const MaestroEID& eid); + friend Maestro_Message& operator>>(Maestro_Message &msg, MaestroEID& eid); + + }; + + std::ostream& operator<<(std::ostream& os, const MaestroEID& eid); + + // typedef for common containers + typedef std::tr1::unordered_map MaestroEID_int_map; + typedef std::tr1::unordered_set MaestroEID_hset; + typedef std::set MaestroEID_set; + typedef std::vector MaestroEID_vec; + + class MaestroEID_list : public MaestroEID_set + { + + public: + + MaestroEID_list(); + MaestroEID_list(const MaestroEID_list& l); + MaestroEID_list(const Maestro_EndpList& l); + virtual ~MaestroEID_list(); + + const MaestroEID_list& operator=(const Maestro_EndpList& l); + + }; + + Maestro_Message& operator<< (Maestro_Message &msg, const MaestroEID_list& l); + Maestro_Message& operator>> (Maestro_Message &msg, MaestroEID_list& l); + std::ostream& operator<<(std::ostream& os, const MaestroEID_list& l); + + typedef std::tr1::unordered_map + MaestroEID_eidlist_map_base; + + // a MaestroEID to MaestroEID_list map + class MaestroEID_eidlist_map : public MaestroEID_eidlist_map_base + { + + public: + + MaestroEID_eidlist_map(); + MaestroEID_eidlist_map(const MaestroEID_eidlist_map& m); + virtual ~MaestroEID_eidlist_map(); + + }; + + Maestro_Message& operator<< (Maestro_Message &msg, const MaestroEID_eidlist_map& m); + Maestro_Message& operator>> (Maestro_Message &msg, MaestroEID_eidlist_map& m); + std::ostream& operator<<(std::ostream& os, const MaestroEID_eidlist_map& m); + +} // namespace av + +#endif // #if !defined(AVANGO_MAESTROEID_H) diff --git a/avango-core/include/avango/Msg.h b/avango-core/include/avango/Msg.h new file mode 100644 index 00000000..d4b73500 --- /dev/null +++ b/avango-core/include/avango/Msg.h @@ -0,0 +1,251 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_MSG_H) +#define AVANGO_MSG_H + +#include +#include +#include + +#include + +#include + +namespace av +{ + class NetNode; + + /** + * Serialization facility for Avango distribution. + * This class is a smart handler for the underlying memory buffer. + */ + class Msg + { + + public: + + enum MsgType + { + relative, // push only changes + absolute // push the complete object + }; + + Msg(); + ~Msg(); + + // not implemented, compiler does the right thing + // copy construction copies the object, but not the buffer + // Msg(const Msg& msg); + // Msg& operator=(const Msg& msg); + + /// copies Msg object and buffer. Cloned object has the same + /// content as this object, but seperate buffer + Msg clone() const; + + void setType(MsgType mt) { mMsgType = mt; } + MsgType getType() const { return mMsgType; } + + /// get byte size of message + size_t getSize(); + /// resize message. newSize can be bigger or smaller than old size + void resize(size_t newSize); + + + /// remove \e bytes from message and put them into \e buffer + void pop(void* buffer, size_t bytes); + /// add raw memory buffer of size \e bytes to end of message + void push(const void* buffer, size_t bytes); + + /// get raw message buffer pointer + unsigned char* getBuffer(); + + /// get NetNode that this message belongs to. Can be 0 is message is not associated with a NetNode yet. + NetNode* getNetNode() const; + /// set NetNode that this message belongs to. + void setNetNode(NetNode* netNode); + + private: + typedef std::vector MessageBuffer; + + Msg(MsgType newMsgType, boost::shared_ptr newBuffer); + + MsgType mMsgType; + + boost::shared_ptr mMsgBuffer; + NetNode* mNetNode; + }; + + + class XDRHandle { + public: + XDRHandle(void* buffer, size_t bufferSize, xdr_op direction) + { xdrmem_create(&mXDR, (caddr_t)buffer, bufferSize, direction); } + ~XDRHandle() + { xdr_destroy(&mXDR); } + + XDR* getXDR() { return &mXDR; } + + private: + XDRHandle(const XDRHandle&); + XDRHandle& operator=(const XDRHandle&); + + XDR mXDR; + }; + + class Field; + class Distributed; + class NetID; + class AnyLink; + class Type; + class Field; + + // bool + void av_pushMsg(Msg& msg, const bool& buf); + void av_popMsg(Msg& msg, bool& buf); + + // int32_t + void av_pushMsg(Msg& msg, const int32_t& buf); + void av_popMsg(Msg& msg, int32_t& buf); + + // std::vector + void av_pushMsg(Msg& msg, const std::vector& buf); + void av_popMsg(Msg& msg, std::vector& buf); + + // uint32_t + void av_pushMsg(Msg& msg, const uint32_t& buf); + void av_popMsg(Msg& msg, uint32_t& buf); + + // std::vector + void av_pushMsg(Msg& msg, const std::vector& buf); + void av_popMsg(Msg& msg, std::vector& buf); + + // int64_t + void av_pushMsg(Msg& msg, const int64_t& buf); + void av_popMsg(Msg& msg, int64_t& buf); + + // std::vector + void av_pushMsg(Msg& msg, const std::vector& buf); + void av_popMsg(Msg& msg, std::vector& buf); + + // uint64_t + void av_pushMsg(Msg& msg, const uint64_t& buf); + void av_popMsg(Msg& msg, uint64_t& buf); + + // std::vector + void av_pushMsg(Msg& msg, const std::vector& buf); + void av_popMsg(Msg& msg, std::vector& buf); + + // float + void av_pushMsg(Msg& msg, const float& buf); + void av_popMsg(Msg& msg, float& buf); + + // std::vector + void av_pushMsg(Msg& msg, const std::vector& buf); + void av_popMsg(Msg& msg, std::vector& buf); + + // double + void av_pushMsg(Msg& msg, const double& buf); + void av_popMsg(Msg& msg, double& buf); + + // std::vector + void av_pushMsg(Msg& msg, const std::vector& buf); + void av_popMsg(Msg& msg, std::vector& buf); + + // AnyLink + void av_pushMsg(Msg& msg, const AnyLink& buf); + void av_popMsg(Msg& msg, AnyLink& buf); + + // Type + void av_pushMsg(Msg& msg, const Type& buf); + void av_popMsg(Msg& msg, Type& buf); + + // Field + void av_pushMsg(Msg& msg, Field* buf); + void av_popMsg(Msg& msg, Field* buf); + + // Distributed + void av_pushMsg(Msg& msg, Distributed* buf); + void av_popMsg(Msg& msg, Distributed* buf); + + // std::string + void av_pushMsg(Msg& msg, const std::string& buf); + void av_popMsg(Msg& msg, std::string& buf); + + // NetID + void av_pushMsg(Msg& msg, const NetID& buf); + void av_popMsg(Msg& msg, NetID& buf); + + template + void av_pushMsg(Msg& msg, const std::pair& val) + { + av_pushMsg(msg, val.first); + av_pushMsg(msg, val.second); + } + + template + void av_popMsg(Msg& msg, std::pair& val) + { + av_popMsg(msg, val.second); + av_popMsg(msg, val.first); + } + + template + void av_pushMsg(Msg& msg, const std::vector& val) + { + typename std::vector::const_iterator it(val.begin()); + + while (it != val.end()) + { + av_pushMsg(msg, *it); + ++it; + + } + av_pushMsg(msg, val.size()); + } + + template + void av_popMsg(Msg& msg, std::vector& val) + { + int count; + + av_popMsg(msg, count); + + std::vector swapVec(count); + + val.swap(swapVec); + + T tmp; + + for (int i = count; i > 0; --i) + { + av_popMsg(msg, tmp); + val[i-1] = tmp; + } + } + +} // namespace av + +#endif // #if !defined(AVANGO_NETMSG_H) diff --git a/avango-core/include/avango/MultiField.h b/avango-core/include/avango/MultiField.h new file mode 100644 index 00000000..333d17b5 --- /dev/null +++ b/avango-core/include/avango/MultiField.h @@ -0,0 +1,463 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_MULTIFIELD_H) +#define AVANGO_MULTIFIELD_H + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) +# include +#endif + +namespace av +{ + + /** + * Multi value holder to be put into a FieldContainer + */ + template + class MultiField : public Field + { + + public: + + typedef Field SuperType; + typedef std::vector ContainerType; + typedef Value ValueType; + + /** + * Event class for field getValue events. + */ + class GetValueEvent : public Event + { + friend class MultiField; + + public: + + /** + * Get the pointer to write the new value to. + * Don't access the pointer outside the callback. + */ + ContainerType* getValuePtr() const { return mValuePtr; } + + protected: + GetValueEvent(const Field *field, ContainerType* value_ptr) : + Event(field), mValuePtr(value_ptr) {} + + private: + ContainerType* mValuePtr; + }; + + /** + * Event class for field setValue events. + */ + class SetValueEvent : public Event + { + friend class MultiField; + + public: + + /** + * Get the new value. + * A reference to the new value is returned to avoid copying. + * Don't access it outside the callback. + */ + const ContainerType& getValue() const { return mValue; } + + protected: + SetValueEvent(Field *field, const ContainerType& value) : + Event(field), mValue(value) {} + + private: + const ContainerType& mValue; + }; + + typedef boost::function GetValueCallback; + typedef boost::function SetValueCallback; + + MultiField() : + Field(), + mHasGetValueCallback(false), + mHasSetValueCallback(false) + {} + + MultiField(const MultiField&) : Field() + {} + + virtual ~MultiField() + {} + + static void initClass(const std::string& classname, const std::string& parentname) + { + if (Type::badType() == sClassTypeId) { + sClassTypeId = Field::registerType(classname, parentname, + new CreateA >()); + } + } + + static Type getClassTypeId() + { + return sClassTypeId; + } + + virtual Type getTypeId() const + { + return sClassTypeId; + } + + void bind(FieldContainer* container, const std::string& name, + bool owned, const ContainerType& init) + { + Field::bind(container, name, owned); + mValue = init; + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + } + + void bind(FieldContainer* container, const std::string& name, bool owned, + const GetValueCallback& get_cb, const SetValueCallback& set_cb) + { + if (!isBound()) + { + SuperType::bind(container, name, owned); + } + + addGetValueCallback(get_cb); + addSetValueCallback(set_cb); + + getValue(); + } + + void bind(FieldContainer* container, const std::string& name, bool owned, + const GetValueCallback& get_cb, const SetValueCallback& set_cb, + const ContainerType& init) + { + addGetValueCallback(get_cb); + addSetValueCallback(set_cb); + + bind(container, name, owned, init); + } + + virtual void setValue(const ContainerType& v) + { + setValue(v, 0); + } + + virtual const ContainerType& getValue() const + { + if (mHasGetValueCallback) + mGetValueCallback(GetValueEvent(this, &mValue)); + return mValue; + } + + virtual void add1Value(const Value& v) + { + getValue(); + mValue.push_back(v); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(false); + } + + virtual void remove1Value(const Value& v) + { + getValue(); + + typename ContainerType::iterator f(std::find(mValue.begin(), mValue.end(), v)); + + if (f != mValue.end()) + { + mValue.erase(f); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(false); + } + } + + virtual bool has1Value(const Value& v) + { + getValue(); + return (std::find(mValue.begin(), mValue.end(), v) != mValue.end()); + } + + /* virtual */ void clear() + { + mValue.clear(); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(false); + } + + virtual int getSize() + { + return static_cast(getValue().size()); + } + + virtual bool isEmpty() + { + return getValue().empty(); + } + + virtual void read(InputStream& is) + { + int count; + + is >> count; + if (!is) + { + return; + } + + ContainerType vec; + for (int i=0; i> val; + vec.push_back(val); + } + setValue(vec); + } + + virtual void write(OutputStream& os) + { + getValue(); + +#if defined(__APPLE__) + os.operator<<(static_cast< typename std::vector::size_type>(mValue.size())); +#endif +#if defined(_WIN32) + // cl of VS 8 apparently not able to resolve os << mValue.size() + os.operator<<(static_cast::size_type>(mValue.size())); +#endif +#if defined(__linux__) + os << mValue.size(); +#endif + + typename ContainerType::const_iterator i(mValue.begin()); + + if (os.isBinaryEnabled()) + { + while (i != mValue.end()) + { + os << (*i); + ++i; + } + } + else + { + (std::ostream&) os << ' '; + + while (i != mValue.end()) + { + os << (*i); + (std::ostream&) os << ' '; + ++i; + } + } + } + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + virtual void push(Msg& msg); + virtual void pop(Msg& msg); +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) + + template friend bool operator==(const MultiField&, const MultiField&); + + /** + * Register callback invoked for a getValue called on this field. + * The callback must take exactly one parameter of GetValueEvent. + */ + void addGetValueCallback(const GetValueCallback& callback) + { + mHasGetValueCallback = true; + mGetValueCallback = callback; + } + + /** + * Remove previously registered field GetValueCallback via its handle. + */ + void removeGetValueCallback(void) + { + mHasGetValueCallback = false; + mGetValueCallback = 0; + } + + /** + * Register callback invoked for a setValue called on this field. + * The callback must take exactly one parameter of SetValueEvent. + */ + void addSetValueCallback(const SetValueCallback& callback) + { + mHasSetValueCallback = true; + mSetValueCallback = callback; + } + + /** + * Remove previously registered field SetValueCallback via its handle. + */ + void removeSetValueCallback(void) + { + mHasSetValueCallback = false; + mSetValueCallback = 0; + } + + /*virtual*/ Field* clone(void) const + { + MultiField* cloned_field = new MultiField; + cloned_field->mValue = mValue; + return cloned_field; + } + + protected: + + virtual void setValue(const ContainerType& v, Field* triggered_from) + { + mValue = v; + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(false, triggered_from); + } + + virtual void pullValue(Field* fromField) + { + pullValueImpl(fromField); + } + + mutable ContainerType mValue; + + private: + + void pullValueImpl(Field* fromField); + + static Type sClassTypeId; + + GetValueCallback mGetValueCallback; + SetValueCallback mSetValueCallback; + + // Even though boost::function provides an empty() method, we track this + // status ourselves as it is quite a bit faster and speed is quite + // important here. + bool mHasGetValueCallback; + bool mHasSetValueCallback; + }; + + template + void av::MultiField::pullValueImpl(av::Field* fromField) + { + if (!fromField->getTypeId().isOfType(MultiField::getClassTypeId())) + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } + setValue(dynamic_cast*>(fromField)->getValue(), fromField); + } + + template<> AV_DLL void av::MultiField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::MultiField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::MultiField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::MultiField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::MultiField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::MultiField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::MultiField::pullValueImpl(av::Field* fromField); + + + template bool + operator==(const MultiField& a, const MultiField& b) + { + return a.getValue() == b.getValue(); + } + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + + template inline void + MultiField::push(Msg& msg) + { + getValue(); + + typename ContainerType::const_iterator i(mValue.begin()); + + while (i != mValue.end()) + { + av_pushMsg(msg, *i); + ++i; + } + + av_pushMsg(msg, static_cast(mValue.size())); + } + + template inline void + MultiField::pop(Msg& msg) + { + uint32_t count; + + av_popMsg(msg, count); + + ContainerType swapVec(count); + + mValue.swap(swapVec); + + Value val; + + for (uint32_t i = count; i > 0; --i) + { + av_popMsg(msg, val); + mValue[i-1] = val; + } + + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); + } + + template<> void MultiField::push(Msg&); + template<> void MultiField::pop(Msg&); + template<> void MultiField::push(Msg&); + template<> void MultiField::pop(Msg&); + template<> void MultiField::push(Msg&); + template<> void MultiField::pop(Msg&); + template<> void MultiField::push(Msg&); + template<> void MultiField::pop(Msg&); + template<> void MultiField::push(Msg&); + template<> void MultiField::pop(Msg&); + template<> void MultiField::push(Msg&); + template<> void MultiField::pop(Msg&); + +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) + +} + +#endif // #if !defined(AVANGO_MULTIFIELD_H) diff --git a/avango-core/include/avango/NetID.h b/avango-core/include/avango/NetID.h new file mode 100644 index 00000000..3d13cea2 --- /dev/null +++ b/avango-core/include/avango/NetID.h @@ -0,0 +1,96 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_NETID_H) +#define AVANGO_NETID_H + +#include +#include + +#ifdef __GNUC__ // GNU C++ stores TR1 headers differently +#include +#else +#include +#endif + + +namespace av +{ + /** + * Unique ID for every node in a net group. + * It consists of the endpoint id and a number. + */ + class NetID + { + + public: + + class Hasher + { + public: + + // this is a very poor hash function. improve it! + size_t operator()(const NetID& id) const + { + return std::tr1::hash()(id.getEID()) + id.getNum(); + } + }; + + NetID(); + NetID(const NetID& ni); + NetID(const std::string& eid, int number); + ~NetID(); + + NetID& operator=(const NetID&); + bool operator==(const NetID& ni) const; + + void set(const std::string& eid, int number); + + int getNum() const; + const std::string& getEID() const; + bool isWellKnown() const; + + bool isNull() const; + void setNull(); + static NetID nullID(); + + friend std::ostream& operator<< (std::ostream& os, const NetID&); + static const int sNetGroupRootNode; + static const int sNetGroupContainerHolder; + + private: + static const int sWellKnownBase; + + std::string mCreator; + int mNumber; + }; + + std::ostream& operator<< (std::ostream& os, const NetID&); + + typedef std::tr1::unordered_set > NetID_set; + +} // namespace av + +#endif // #if !defined(AVANGO_NETID_H) diff --git a/avango-core/include/avango/NetInfo.h b/avango-core/include/avango/NetInfo.h new file mode 100644 index 00000000..bc31ff63 --- /dev/null +++ b/avango-core/include/avango/NetInfo.h @@ -0,0 +1,65 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_NETINFO_H) +#define AVANGO_NETINFO_H + +#include + +namespace av +{ + class Distributed; + class NetNode; + + // per node bookkeeping + + class NetInfo { + + friend class Distributed; + + public: + + NetInfo(const NetID&, const NetNode*); + ~NetInfo(); + + const NetID& getId() const; + const NetNode* getNode() const; + NetNode* getNode(); + + private: + + NetID mId; + NetNode* mNode; + + // declared but never defined + NetInfo(); + NetInfo(const NetInfo&); + const NetInfo& operator=(const NetInfo&); + + }; + +} // namespace av + +#endif // #if !defined(AVANGO_NETINFO_H) diff --git a/avango-core/include/avango/NetLock.h b/avango-core/include/avango/NetLock.h new file mode 100644 index 00000000..287ec016 --- /dev/null +++ b/avango-core/include/avango/NetLock.h @@ -0,0 +1,72 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#ifndef AV_NETLOCK_H +#define AV_NETLOCK_H + +#include + +namespace av { + /** + * This class implements a building block for locking over the distribution group. + * The process requesting the network lock writes a unique id into the "Request" field. + * If the same name shows up in the "Granted" field, this process owns the lock. + * It can then release the lock by writing the same unique id into the "Release" field, + * which resets the "Granted" field to the empty string. + * Short: This is cooperative locking, you only have the lock when your id shows up in the "Granted" field. + */ + class NetLock : public FieldContainer { + + AV_FC_DECLARE(); + + public: + NetLock(); + protected: + /* virtual */~NetLock(); + public: + /** + * Request the lock. Write an id unique for this process in here, preferably the EID + * (\see av::NetNode). + */ + SFString Request; + /** + * Output field. This contains the id of the process that is holding the lock. + */ + SFString Granted; + /** + * Release the Lock. You have to put the same id in here that you used for the request, and + * your process has to have acquired the lock ( your id is in the "Granted" field ) + */ + SFString Release; + + void fieldHasChanged(const Field& field); + void evaluate(); + private: + bool mRelease; + bool mRequest; + }; +} + +#endif /*AV_NETLOCK_H*/ diff --git a/avango-core/include/avango/NetMap.h b/avango-core/include/avango/NetMap.h new file mode 100644 index 00000000..00302c18 --- /dev/null +++ b/avango-core/include/avango/NetMap.h @@ -0,0 +1,87 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_NETMAP_H) +#define AVANGO_NETMAP_H + +#include +#include + +#ifdef __GNUC__ // GNU C++ stores TR1 headers differently +#include +#else +#include +#endif + +// #include +#include + +namespace av +{ + class NetID; + + // a catalog of all objects playing in netland, exept well-kowns + + class NetMap { + + public: + + NetMap(); + virtual ~NetMap(); + + void addSlot(const std::string& eid); + void removeSlot(const std::string& eid); + bool slotExists(const std::string& eid) const; + + void registerObj(const Link& obj); + void unregisterObj(const Link& obj); + + bool lookup(const NetID& id, Link& result) const; + bool lookup(const std::string& eid, std::vector >& result) const; + bool lookup(std::vector >& result) const; + + bool lookupExcept(const std::string& eid, std::vector >& result) const; + + void removeAllSlots(); + void removeAllSlotsExcept(const std::string& eid); + + void emptySlot(const std::string& eid); + void emptyAllSlots(); + void emptyAllSlotsExcept(const std::string& eid); + + void dump(std::ostream& os) const; + + private: + + typedef std::tr1::unordered_map > IntDstMap; + typedef std::tr1::unordered_map EIDMapMap; + + EIDMapMap mEIDMap; + + }; + +} // namespace av + +#endif // #if !defined(AVANGO_NETMAP_H) diff --git a/avango-core/include/avango/NetNode.h b/avango-core/include/avango/NetNode.h new file mode 100644 index 00000000..fd103b5c --- /dev/null +++ b/avango-core/include/avango/NetNode.h @@ -0,0 +1,281 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_NETNODE_H) +#define AVANGO_NETNODE_H + +#include +#include +#include +#include +#include + +#ifdef __GNUC__ // GNU C++ stores TR1 headers differently +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +//#include +#include + +namespace av +{ + class NetGroup; + + typedef std::tr1::unordered_map, NetID::Hasher> NetIDDstMap; + typedef std::deque MsgDeq; + typedef std::vector > MaestroStateUpdateList; + + /** + * This class is the link between avango and the group communication toolkit. It represents the avango process in the named group + * this NetNode joins. + */ + class NetNode + { + + public: + + /** + * Create a new group member and join the group + * @param groupName The group to join + */ + void join(const std::string& groupName); + + /** + * Leave the currently joined group + */ + void leave(); + + /** + * Wether we are connected to some group or not + * @return true if connected, false otherwise + */ + bool onAir() const; + + /** + * Look for a distributed node which matches the specified id + * @param id Id of the wanted node + * @param result The found node + * @return true if node was found, false otherwise + */ + bool lookup(const NetID& id, Link& result); + + /** + * Make an local object distributed + * @param obj The object that should be shared + */ + void distributeObject(Link obj); + /** + * Make a distributed object local + * @param obj The distributed object + */ + void undistributeObject(Link obj); + + /** + * Specialized version of distributeObject, used for Python binding + * @param obj + */ + void distributeFieldContainer(Link obj); + /** + * Specialized version of undistributeObject, used for Python binding + * @param obj + */ + void undistributeFieldContainer(Link obj); + + /** + * Tell the group that this object has changed. Schedules object updates for group distribution + * @param obj The object that has changed + */ + void updateDistributedObject(const Link& obj); + + /** + * Handle network callbacks. All callbacks which have occured until now + * are handled in the correct order. + */ + void handleNetworkSends(); + void handleNetworkReceives(); + + /** + * This function is called from the network side when this process has successfully joined the group + * @param myeid The EndpointID of this process + */ + void joined(const std::string& myeid); + + /** + * This function is called from the network side when the group is blocked for a view change + * (processes enter or leave the group) + */ + void block(); + /** + * This function is called from the network side when the group is unblocked for a view change + * (processes enter or leave the group) + */ + void unblock(); + + void queueStateFragment(const std::string& fragment, Msg& stateMsg); + void queueRemoveFragment(const std::string& fragment); + void setStateFragment(const std::string& fragment, Msg& stateMsg); + void getStateFragment(const std::string& fragment, Msg&stateMsg); + void removeStateFragment(const std::string& fragment); + void receiveMessage(const std::string& origin, Msg& msg); + void exitCompleted(); + void acceptNewView(const std::vector& members, + const std::vector& newMembers, + const std::vector& departedMembers, + Msg& msg); + + // return the enpoint id of the group we joined + const std::string& netEID() const ; + + void consumeMessage(Msg& msg); + + protected: + + // hide ctor and dtor + NetNode(); + virtual ~NetNode(); + + // registration of well known nodes. only when registered, well-known nodes can + // receive and send update messages. because they are well known, creation and + // destruction is not announced via the net. every participant is supposed to + // to create his own versions of these nodes. + void registerWellKnown(const Link& obj, const NetID& id); + void unregisterWellKnown(const Link& obj); + + // registration of distributables. an object can only be distributed in one + // group. all other group members will be able to see and modify a registered + // object. an unregistered object is only visible to the creator. + void registerObj(const Link& obj); + void registerObj(const Link& obj, const NetID& id); + void unregisterObj(const Link& obj); + + // announce locally made changes to the group + void notifyGroup(); + + // create messages for every occassion + void makeCreateMessage(Msg& msg, const Link& obj); + void makeUpdateMessage(Msg& msg, const Link& obj); + void makeDeleteMessage(Msg& msg, const Link& obj); + + // take them from the net and do the right thing + void consumeReceivedMessages(); + void consumeCreateMessage(Msg& msg); + void consumeUpdateMessage(Msg& msg); + void consumeDeleteMessage(Msg& msg); + void consumePackedMessage(Msg& msg); + + // the state transfer is special + void makeStateTransferMessage(Msg& msg); + void consumeStateTransferMessage(Msg& msg); + + // tell our clients we joined + virtual void _join(const std::string& fragment) {} + + // overloaded from NetNode to react to view changes + virtual void _acceptNewView(const std::vector& members, + const std::vector& newMembers, + const std::vector& departedMembers) {} + + // overloaded to participate in state transfers + virtual void _getStateFragment(const std::string& , Msg& ) {} + virtual void _setStateFragment(const std::string& , Msg& ) {} + virtual void _removeStateFragment(const std::string& ) {} + + private: + + // don't allow copy ctor and assignment otor + NetNode(const NetNode&); + NetNode& operator=(const NetNode&); + + // message type tokens + static const unsigned int sCreateMsg; + static const unsigned int sUpdateMsg; + static const unsigned int sDeleteMsg; + static const unsigned int sPackedMsg; + static const unsigned int sStateTransferMsg; + + // generate a new id, which is unique with respect to this group + // it consists of the eid of the creator and a number + std::string mEID; + int mIdCounter; + NetID generateUniqueId(); + + // the actual group member, derived from some maestro class + NetGroup* mMember; + int mNumMembers; + + // all well-known objects in a map for fast lookup by id + NetIDDstMap mWellKnownObjects; + + // all other distributed objects + NetMap mObjectMap; + + // send over the changes + void notifyCreations(); + void notifyUpdates(); + void notifyDeletes(); + + // messages are pending to be send for these objects + DistributedSet mPendingCreations; + DistributedSet mPendingUpdates; + DistributedSet mPendingDeletes; + + // messages we receive while not being a server are stacked up here for later processing + MsgDeq mReceivedMessages; + boost::mutex mMessageMutex; + bool mBlocked; + + typedef std::vector > StateUpdateList; + typedef std::vector StateRemoveList; + + StateUpdateList mStateUpdates; + StateRemoveList mStateRemoves; + void applyStateFragments(); + + // ensemble command line option interface + + protected: + + static std::map > sEnsOptions; + static char** sEnsOptionsArgv; + static char** getEnsOptionsArgv(); + + public: + + static void setEnsOption(const std::string& option, const std::string& value); + static bool getEnsOption(const std::string& option, std::string& value); + + }; + +} // namespace av + +#endif // #if !defined(AVANGO_NETNODE_H) diff --git a/avango-core/include/avango/Object.h b/avango-core/include/avango/Object.h new file mode 100644 index 00000000..24a8aaa1 --- /dev/null +++ b/avango-core/include/avango/Object.h @@ -0,0 +1,24 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#error This class was removed. Use FieldContainer instead. diff --git a/avango-core/include/avango/ObjectValue.h b/avango-core/include/avango/ObjectValue.h new file mode 100644 index 00000000..6a770049 --- /dev/null +++ b/avango-core/include/avango/ObjectValue.h @@ -0,0 +1,120 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_OBJECTVALUE_H) +#define AVANGO_OBJECTVALUE_H + +#include + +#include +#include + +namespace av +{ + /** + * The ObjectValue template encapsulates a single value in an AVANGO field + * container. + */ + template class ObjectValue : public FieldContainer + { + + public: + + typedef T ValueType; + + SingleField Value; + + ObjectValue() + { + AV_FC_ADD_FIELD(Value, ValueType()); + } + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~ObjectValue() + {} + + public: + + static void initClass() + { + if (!isTypeInitialized()) + { + FieldContainer::initClass(); + + sClassTypeId = Type::createType(FieldContainer::getClassTypeId(), + sClassTypeName, + new CreateA >, + true); + + sClassTypeId.setDistributable(true); + } + } + + static Type getClassTypeId() + { + AV_ASSERT(Type::badType() != sClassTypeId); + return sClassTypeId; + } + + static bool isTypeInitialized() + { + return Type::badType() != sClassTypeId; + } + + Type getTypeId() const + { + AV_ASSERT(Type::badType() != sClassTypeId); + return sClassTypeId; + } + + private: + + static Type sClassTypeId; + static const std::string sClassTypeName; // initialized in specialization + + }; + + template Type ObjectValue::sClassTypeId = Type::badType(); + + template class AV_DLL ObjectValue; + template class AV_DLL ObjectValue; + template class AV_DLL ObjectValue; + template class AV_DLL ObjectValue; + template class AV_DLL ObjectValue; + template class AV_DLL ObjectValue >; + template class AV_DLL ObjectValue; + + typedef ObjectValue BoolObject; + typedef ObjectValue IntObject; + typedef ObjectValue UIntObject; + typedef ObjectValue FloatObject; + typedef ObjectValue DoubleObject; + typedef ObjectValue > ObjectObject; + typedef ObjectValue StringObject; +} + +#endif // #if !defined(AVANGO_OBJECTVALUE_H) diff --git a/avango-core/include/avango/OutputStream.h b/avango-core/include/avango/OutputStream.h new file mode 100644 index 00000000..f43fa42d --- /dev/null +++ b/avango-core/include/avango/OutputStream.h @@ -0,0 +1,164 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_OUTPUTSTREAM_H) +#define AV_OUTPUTSTREAM_H + +/** + * \file + * \ingroup av + */ + +#include "windows_specific.h" + +#if defined(_MSC_VER) + #include "stdint_replacement.h" +#else + #include +#endif + +#include +#include +#include + + +namespace av +{ + + class WriteAction; + + /** + * Class for writing Avango Objects to a stream. This is used + * for persistence and network distribution. + * + * \ingroup av + */ + class AV_DLL OutputStream : public std::ostream + { + + public: + + /** + * Constructor + */ + OutputStream(); + + /** + * Construct an OutputStream from an existing ostream + */ + OutputStream(std::ostream&); + + /** + * Construct an OutputStream from an existing streambuf + */ + OutputStream(std::streambuf*); + + /** + * Assign an ostream to an OutputStream + */ + OutputStream& operator=(std::ostream&); + + /** + * Assign a streambuf to an OutputStream + */ + OutputStream& operator=(std::streambuf*); + + /** + * Switch for enabling binary mode + */ + void enableBinary(bool on); + + /** + * Return \c true if the OutputStream is in binary mode + */ + bool isBinaryEnabled() const; + + /** + * Set WriteAction for this stream. + */ + void setWriteAction(WriteAction* writeAction); + + /** + * Get WriteAction for this stream. + */ + av::WriteAction* getWriteAction(); + + private: + + av::WriteAction* mWriteAction; + bool mBinary; + + }; + + /** + * Write end-of-line to the OutputStream. + * + * \ingroup av + */ + AV_DLL OutputStream& endl(OutputStream&); + + /** + * Flush the OutputStream. + * + * \ingroup av + */ + AV_DLL OutputStream& flush(OutputStream&); + + // basic types + AV_DLL OutputStream& operator<<(OutputStream& os, const int16_t& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const uint16_t& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const int32_t& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const uint32_t& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const int64_t& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const uint64_t& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const float& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const double& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const bool& value); + AV_DLL OutputStream& operator<<(OutputStream& os, const std::string& value); + + template OutputStream& + operator<<(OutputStream& os, const std::pair& value) + { + return os << value.first << value.second; + } + + template OutputStream& operator<<(OutputStream& os, const std::vector& value) + { + os << value.size(); + + typename std::vector::const_iterator it(value.begin()); + + while (it != value.end()) { + os << *it; + + ++it; + } + + return os; + } + +} + +#endif // #if !defined(AV_OUTPUTSTREAM_H) diff --git a/avango-core/include/avango/Reader.h b/avango-core/include/avango/Reader.h new file mode 100644 index 00000000..065ef729 --- /dev/null +++ b/avango-core/include/avango/Reader.h @@ -0,0 +1,74 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_READER_H) +#define AV_READER_H + +#include +#include + +#include + +namespace av +{ + class Field; + class InputStream; + class Base; + + /** + * Reads Avango objects from a file or an InputStream. + */ + class AV_DLL Reader + { + + public: + + typedef std::vector > BaseLinkVec; + typedef std::map > StringBaseMap; + typedef std::map > ConnectionMap; + + Reader(); + ~Reader(); + + Base* readFromFile(const std::string& filename); + Base* readObject(InputStream&); + + Base* lookupObject(const std::string& id); + void addConnection(Field* toField, const std::string& fromId, int fromIndex); + + void enableBinary(bool bin); + bool isBinaryEnabled(); + + private: + + bool mBinary; + + StringBaseMap mObjectMap; + ConnectionMap mConnectionMap; + }; + +} + +#endif // #if !defined(AVANGO_LIBFP_LIBFP_FPREADER_H) diff --git a/avango-core/include/avango/SConscript b/avango-core/include/avango/SConscript new file mode 100644 index 00000000..6e5473a1 --- /dev/null +++ b/avango-core/include/avango/SConscript @@ -0,0 +1,73 @@ +# -*- Mode:Python -*- + +########################################################################## +# # +# This file is part of AVANGO. # +# # +# Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der # +# angewandten Forschung (FhG), Munich, Germany. # +# # +# AVANGO is free software: you can redistribute it and/or modify # +# it under the terms of the GNU Lesser General Public License as # +# published by the Free Software Foundation, version 3. # +# # +# AVANGO is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU Lesser General Public # +# License along with AVANGO. If not, see . # +# # +########################################################################## + +import avango.build + +SConscript('logging/SConscript') + +headers = Split(''' + Action.h + Application.h + Assert.h + Base.h + ContainerPool.h + Create.h + Distributed.h + Doxygen.h + Field.h + FieldContainer.h + FieldContainerHelper.h + FieldRef.h + Init.h + InputStream.h + Link.h + Logger.h + MultiField.h + Object.h + ObjectValue.h + OutputStream.h + Reader.h + Semaphore.h + SingleField.h + Singleton.h + StandardFields.h + TimeSensor.h + Type.h + Typed.h + WriteAction.h + windows_specific.h + stdint_replacement.h + ''') + +if avango.build.Environment()['DISTRIBUTION_SUPPORT']: + headers += Split(''' + MaestroEID.h + NetID.h + NetInfo.h + NetLock.h + NetMap.h + Msg.h + NetNode.h + ''') + +Alias('install-core', Install(avango.build.get_include_path('avango'), headers)) diff --git a/avango-core/include/avango/Semaphore.h b/avango-core/include/avango/Semaphore.h new file mode 100644 index 00000000..59621809 --- /dev/null +++ b/avango-core/include/avango/Semaphore.h @@ -0,0 +1,129 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_SEMAPHORE_H) +#define AVANGO_SEMAPHORE_H + +#include +#include + + +#if BOOST_VERSION > 103800 +#include +namespace av +{ + typedef boost::condition_variable condition; +} +#else +#include +namespace av +{ + typedef boost::condition condition; +} +#endif + +#include "windows_specific.h" + +namespace av +{ + /** + * Semaphore implementation using boost::mutex + * + * \ingroup av + */ + class AV_DLL Semaphore + { + public: + + Semaphore(unsigned int initial = 1); + ~Semaphore(); + + /** + * If semaphore value is > 0 then decrement it and carry on. If it's + * already 0 then block. + */ + void wait(); + + /** + * If semaphore value is > 0 then decrement it and return 1 (true). + * If it's already 0 then return 0 (false). + */ + int trywait(); + + /** + * If any threads are blocked in wait(), wake one of them up. Otherwise + * increment the value of the semaphore. + */ + void post(); + + /** + * Return semaphore value. + */ + int snapshot(); + + private: + + // dummy copy constructor and operator= to prevent copying + Semaphore(const Semaphore&); + const Semaphore& operator=(const Semaphore&); + + av::condition mCondition; + boost::mutex mMutex; + int mValue; + + }; + + /** + * Scoped semaphore lock + * + * \ingroup av + */ + class SemaphoreLock { + + public: + + SemaphoreLock(Semaphore& s) : mSemaphore(s) + { + mSemaphore.wait(); + } + + ~SemaphoreLock() + { + mSemaphore.post(); + } + + private: + + // dummy copy constructor and operator= to prevent copying + SemaphoreLock(const SemaphoreLock&); + const SemaphoreLock& operator=(const SemaphoreLock&); + + Semaphore& mSemaphore; + + }; + +} + +#endif // #if !defined(AVANGO_SEMAPHORE_H) diff --git a/avango-core/include/avango/SingleField.h b/avango-core/include/avango/SingleField.h new file mode 100644 index 00000000..29c948c1 --- /dev/null +++ b/avango-core/include/avango/SingleField.h @@ -0,0 +1,361 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_SINGLEFIELD_H) +#define AVANGO_SINGLEFIELD_H + +#include + +#include + +#include +#include +#include +#include + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) +# include +#endif + +namespace av +{ + + /** + * Single value holder to be put into a FieldContainer + */ + template + class SingleField : public Field + { + + /** + * The only purpose of this method is to validate the requirements + * SingleField puts on the underlying value type. + * Having a volatile guard set to false hopefully forces the compiler + * to generate but never execute the included code. + */ + bool validateRequirements() const + { + volatile bool guard(false); + + if (guard) + { + Value v; + OutputStream os; os << v; + InputStream is; is >> v; + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + Msg msg; + av_pushMsg(msg, v); + av_popMsg(msg, v); +#endif + } + return true; + } + + public: + + typedef Field SuperType; + typedef Value ValueType; + + /** + * Event class for field getValue events. + */ + class GetValueEvent : public Event + { + friend class SingleField; + + public: + + /** + * Get the pointer to write the new value to. + * Don't access the pointer outside the callback. + */ + ValueType* getValuePtr() const { return mValuePtr; } + + protected: + GetValueEvent(const Field *field, ValueType* value_ptr) : + Event(field), mValuePtr(value_ptr) {} + + private: + ValueType* mValuePtr; + }; + + /** + * Event class for field setValue events. + */ + class SetValueEvent : public Event + { + friend class SingleField; + + public: + + /** + * Get the new value. + * A reference to the new value is returned to avoid copying. + * Don't access it outside the callback. + */ + const ValueType& getValue() const { return mValue; } + + protected: + SetValueEvent(Field *field, const ValueType& value) : + Event(field), mValue(value) {} + + private: + const ValueType& mValue; + }; + + typedef boost::function GetValueCallback; + typedef boost::function SetValueCallback; + + SingleField() : + Field(), + mValue(Value()), + mHasGetValueCallback(false), + mHasSetValueCallback(false) + { + AV_ASSERT(validateRequirements()); + } + + SingleField(const SingleField&): Field() + { + AV_ASSERT(validateRequirements()); + } + + virtual ~SingleField() + {} + + static void initClass(const std::string& classname, const std::string& parentname) + { + if (Type::badType() == sClassTypeId) + { + sClassTypeId = Field::registerType(classname, parentname, + new CreateA >); + } + } + + static Type getClassTypeId() + { + return sClassTypeId; + } + + virtual Type getTypeId() const + { + return sClassTypeId; + } + + void bind(FieldContainer* container, const std::string& name, bool owned, const Value& init) + { + Field::bind(container, name, owned); + mValue = init; + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + } + + void bind(FieldContainer* container, const std::string& name, bool owned, + const GetValueCallback& get_cb, const SetValueCallback& set_cb) + { + if (!isBound()) + { + SuperType::bind(container, name, owned); + } + + addGetValueCallback(get_cb); + addSetValueCallback(set_cb); + + getValue(); + } + + void bind(FieldContainer* container, const std::string& name, bool owned, + const GetValueCallback& get_cb, const SetValueCallback& set_cb, + const Value& init) + { + addGetValueCallback(get_cb); + addSetValueCallback(set_cb); + + bind(container, name, owned, init); + } + + virtual void setValue(const Value& v) + { + setValue(v, 0); + } + + virtual const Value& getValue() const + { + if (mHasGetValueCallback) + mGetValueCallback(GetValueEvent(this, &mValue)); + return mValue; + } + + /* virtual */ void clear() + { + setValue(Value()); + } + + virtual void read(InputStream& is) + { + Value val; + is >> val; + setValue(val); + } + + virtual void write(OutputStream& os) + { +#if !defined(_WIN32) + os << getValue(); +#else + // cl of VS 8 apparently not able to resolve os << getValue(). + Value val; + val = getValue(); + av::operator<<( static_cast(os), static_cast< Value >( val )); +#endif + } + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + virtual void push(Msg& msg) + { + getValue(); + av_pushMsg(msg, mValue); + } + + virtual void pop(Msg& msg) + { + av_popMsg(msg, mValue); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); + } +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) + + template friend bool operator==(const SingleField&, const SingleField&); + + /** + * Register callback invoked for a getValue called on this field. + * The callback must take exactly one parameter of GetValueEvent. + */ + void addGetValueCallback(const GetValueCallback& callback) + { + mHasGetValueCallback = true; + mGetValueCallback = callback; + } + + /** + * Remove previously registered field GetValueCallback via its handle. + */ + void removeGetValueCallback(void) + { + mHasGetValueCallback = false; + mGetValueCallback = 0; + } + + /** + * Register callback invoked for a setValue called on this field. + * The callback must take exactly one parameter of SetValueEvent. + */ + void addSetValueCallback(const SetValueCallback& callback) + { + mHasSetValueCallback = true; + mSetValueCallback = callback; + } + + /** + * Remove previously registered field SetValueCallback via its handle. + */ + void removeSetValueCallback(void) + { + mHasSetValueCallback = false; + mSetValueCallback = 0; + } + + /*virtual*/ Field* clone(void) const + { + SingleField* cloned_field = new SingleField; + cloned_field->mValue = mValue; + return cloned_field; + } + + protected: + + virtual void setValue(const Value& v, Field* triggered_from) + { + mValue = v; + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(false, triggered_from); + } + + virtual void pullValue(Field* fromField) + { + pullValueImpl(fromField); + } + + mutable Value mValue; + + private: + + void pullValueImpl(Field* fromField); + + static Type sClassTypeId; + + GetValueCallback mGetValueCallback; + SetValueCallback mSetValueCallback; + + // Even though boost::function provides an empty() method, we track this + // status ourselves as it is quite a bit faster and speed is quite + // important here. + bool mHasGetValueCallback; + bool mHasSetValueCallback; + }; + + template inline bool + operator==(const SingleField& a, const SingleField& b) + { + return a.getValue() == b.getValue(); + } + + template + void av::SingleField::pullValueImpl(av::Field* fromField) + { + if (!fromField->getTypeId().isOfType(SingleField::getClassTypeId())) + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } + setValue(dynamic_cast*>(fromField)->getValue(), fromField); + } + + template<> AV_DLL void av::SingleField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::SingleField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::SingleField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::SingleField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::SingleField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::SingleField::pullValueImpl(av::Field* fromField); + template<> AV_DLL void av::SingleField::pullValueImpl(av::Field* fromField); + +} + +#endif // #if !defined(AVANGO_SINGLEFIELD_H) diff --git a/avango-core/include/avango/Singleton.h b/avango-core/include/avango/Singleton.h new file mode 100644 index 00000000..304a923e --- /dev/null +++ b/avango-core/include/avango/Singleton.h @@ -0,0 +1,176 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_SINGLETON_H) +#define AVANGO_SINGLETON_H + +#include +#include +#include +#include +#include + +namespace av +{ + template + class DefaultLifeTime + { + public: + static void onDeadReference() { throw std::logic_error("Access to dead singleton"); } + static void scheduleDestruction(T*, void (*pFun)()) { std::atexit(pFun); } + }; + + template class CreateUsingNew //do not use for arrays + { + public: + static T* create() { return new T(); } + static void destroy(T* inType) { delete inType; inType = 0; } //@note: this is not intended to be used on arrays! + protected: + ~CreateUsingNew();//do not allow CreateUsingNew* pCreator = &foo; delete pCreator->undef behave + }; + + template + class SingleThreaded + { + public: + class Lock //fake lock + { + public: + Lock() { ; } + }; + typedef T VolatileType; //ensure optimal variant for single threaded environment + }; + + template + class MultiThreaded + { + public: + class Lock + { + public: + typedef boost::mutex::scoped_lock ScopeLock; + Lock(); + private: + ScopeLock mGuard; + }; + typedef volatile T VolatileType; //ensure compiler does get hints what we are trying to do + static boost::mutex sConstructionMutex; + }; + + template MultiThreaded::Lock::Lock() : + mGuard(sConstructionMutex) + { + } + + template boost::mutex MultiThreaded::sConstructionMutex; + + template class CreationPolicy = CreateUsingNew, + template class LifeTimePolicy = DefaultLifeTime, + template class ThreadingModel = SingleThreaded> + class Singleton + { + public: + typedef typename ThreadingModel::VolatileType InstanceTypePtr; //T or volatile T, depending on threading model + typedef T Type; + + static Type& get() //no exposing of raw pointer to assure no delete call on ValueType + { + // FIXME This is potentially not thread-safe if access to sInstance is + // non-atomic. Better use boost::call_once(). + if ( !sInstance) + { + typename ThreadingModel::Lock lock; + if ( !sInstance) + { + if (sIsDead) + { + LifeTimePolicy::onDeadReference(); + sIsDead = false; + } + sInstance = CreationPolicy::create(); + LifeTimePolicy::scheduleDestruction(sInstance, + &destroySingleton); + } + } + return *sInstance; + } + + static boost::shared_ptr getAsSharedPtr() + { + return boost::shared_ptr(&get(), NullDeleter()); + } + private: + + static void destroySingleton(); + + Singleton(); + Singleton(const Singleton&); + Singleton& operator=(const Singleton&); //no assignment + + // boost::shared_ptr must not delete the singleton + class NullDeleter + { + public: + void operator()(void const *) const {} + }; + + static InstanceTypePtr sInstance; + static bool sIsDead; + }; + + template < + typename T, + template class C, + template class L, + template class M + > + bool Singleton::sIsDead = false; + + template < + typename T, + template class C, + template class L, + template class M + > + typename Singleton::InstanceTypePtr Singleton::sInstance = 0; + + template + < + class T, + template class CreationPolicy, + template class L, + template class M + > + void Singleton::destroySingleton() + { + AV_ASSERT(!sIsDead); + CreationPolicy::destroy(sInstance); + sInstance = 0; + sIsDead = true; + } + +} // namespace av + +#endif // #if !defined(AVANGO_SINGLETON_H) diff --git a/avango-core/include/avango/StandardFields.h b/avango-core/include/avango/StandardFields.h new file mode 100644 index 00000000..22e70b20 --- /dev/null +++ b/avango-core/include/avango/StandardFields.h @@ -0,0 +1,90 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_STANDARDFIELDS_H) +#define AVANGO_STANDARDFIELDS_H + +#include + +#include +#include +#include + +namespace av +{ +#ifdef AV_INSTANTIATE_FIELD_TEMPLATES + template class AV_DLL SingleField; + template class AV_DLL MultiField; + + template class AV_DLL SingleField; + template class AV_DLL MultiField; + + template class AV_DLL SingleField; + template class AV_DLL MultiField; + + template class AV_DLL SingleField; + template class AV_DLL MultiField; + + template class AV_DLL SingleField; + template class AV_DLL MultiField; + + template class AV_DLL SingleField; + template class AV_DLL MultiField; + + template class AV_DLL SingleField; + template class AV_DLL MultiField; + + template class AV_DLL SingleField; + template class AV_DLL MultiField; +#endif + + typedef SingleField SFBool; + typedef MultiField MFBool; + + typedef SingleField SFDouble; + typedef MultiField MFDouble; + + typedef SingleField SFFloat; + typedef MultiField MFFloat; + + typedef SingleField SFInt; + typedef MultiField MFInt; + + typedef SingleField SFLong; + typedef MultiField MFLong; + + typedef SingleField SFUInt; + typedef MultiField MFUInt; + + typedef SingleField SFULong; + typedef MultiField MFULong; + + typedef SingleField SFString; + typedef MultiField MFString; + + void AV_DLL initStandardFields(); +} + +#endif // #if !defined(AVANGO_STANDARDFIELDS_H) diff --git a/avango-core/include/avango/TimeSensor.h b/avango-core/include/avango/TimeSensor.h new file mode 100644 index 00000000..8e7d125a --- /dev/null +++ b/avango-core/include/avango/TimeSensor.h @@ -0,0 +1,77 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_TIMESENSOR_H) +#define AVANGO_TIMESENSOR_H + +#include + +namespace av +{ + + /** + * Simple time sensor. + * The reference time is initialized with the current real time on + * instantiation but may be set to a user-defined value. + * + * RealTime is an adaptor for gettimeofday() always containg + * the current time and is touched in evaluate(). + * + * Time is updated in evaluate(). + * + * \ingroup av + */ + class AV_DLL TimeSensor : public FieldContainer + { + AV_FC_DECLARE(); + + public: + + TimeSensor(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~TimeSensor(); + + public: + + /// Time in seconds since 1970-01-01 00:00:00 UTC + SFDouble RealTime; + + /// Time reference value in seconds since 1970-01-01 00:00:00 UTC + SFDouble ReferenceTime; + + /// Time in seconds since ReferenceTime + SFDouble Time; + + virtual void evaluate(); + }; + +} // namespace av + +#endif // #if !defined(AVANGO_TIMESENSOR_H) diff --git a/avango-core/include/avango/Type.h b/avango-core/include/avango/Type.h new file mode 100644 index 00000000..3abd09d3 --- /dev/null +++ b/avango-core/include/avango/Type.h @@ -0,0 +1,313 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_TYPE_H) +#define AV_TYPE_H + +/** + * \file + * \ingroup av + */ + +#include "windows_specific.h" + +#if defined(_MSC_VER) + #include "stdint_replacement.h" +#else + #include +#endif // _MSC_VER + +#include +#include +#include + +#include +#include + + +namespace av +{ + + class Typed; + class Create; + + /** + * Encapsulates the type information for runtime typing. + * The Type class keeps track of runtime type information in Avango. + * Each type is associated with a given name, so lookup is possible in + * either direction. + * + * Many Avango classes request a unique Type when they are initialized. + * This type can then be used to find out the actual class of an + * instance when only its base class is known, or to obtain an instance + * of a particular class given its type or name. + * + * \todo Check if mTypeSpec can be changed to be a normal c++ class + * + * \ingroup av + */ + class AV_DLL Type + { + + public: + + /** + * Hash Functor for using Type in hash_map. + */ + class Hasher + { + public: + inline size_t operator()(const Type& t) const + { + return t.getId(); + } + }; + + /** + * List of Types type definition. This is used as return value of + * some functions. + */ + typedef std::vector TypeList; + + /** + * Constructor + */ + Type(); + + /** + * Copy Constructor + */ + Type(const Type& other); + + /** + * Construct a Type from its 32 bit integer representation. This + * is useful for file or network i/o involving instancies of Type}. + */ + Type(uint32_t id); + + /** + * Destructor + */ + ~Type(); + + /** + * Assignment Operator + */ + const Type& operator=(const Type& rhs); + + /** + * Init run-time type system. + * This effectively clears the type registry removing all registered + * types. + */ + static void init(); + + /** + * Returns an always-illegal type. Useful for returning errors. + */ + static Type badType(); + + /** + * Returns the type associated with the given name. + */ + static Type getByName(const std::string& typeName); + + /** + * %Create and register new type. + */ + static Type createType(Type parentType, const std::string& typeName, + Create* creator, bool typeIsPublic); + + /** + * %Create and register new abstract type. + */ + static Type createAbstractType(Type parentType, + const std::string& typeName, + bool typeIsPublic); + + /** + * Returns \c true if the type is a bad type. + */ + bool isBad() const; + + /** + * Returns \c true if the type is derived from type \c typeToCheck. + */ + bool isDerivedFrom(Type typeToCheck) const; + + /** + * Returns \c true if the type is derived from or is equal to type + * \c typeToCheck. + */ + bool isOfType(Type typeToCheck) const; + + /** + * Returns \c true if the type is not an internal type. + */ + bool isPublic() const; + + /** + * Some types are able to create instances; for example, most nodes + * (those which are not abstract classes) can be created this + * way. This method returns \c true if the type supports such + * creation. + */ + bool canCreate() const; + + /** + * Returns the name associated with a type. + */ + const std::string& getName() const; + + /** + * Returns a list of all types derived from the given type. + */ + TypeList getAllDerivedFrom() const; + + /** + * Returns the parent type of the given type. + */ + Type getParent() const; + + /** + * Returns \c true if the type is the same as \c rhs. + */ + bool operator==(const Type rhs) const; + + /** + * Returns \c true if the type is the same as \c rhs. + */ + bool operator!=(const Type rhs) const; + + /** + * Returns \c true if the id of the type is less than the id of + * \c rhs. + */ + bool operator<(const Type rhs) const; + + /** + * Coerce a Type to unsigned int. This is useful for file or + * network i/o involving instancies of Type + * + * \todo Check if uint32_t() can be removed + */ + operator uint32_t() const; + + /** + * Coerce a Type to unsigned int. This is useful for file or + * network i/o involving instancies of Type + */ + uint32_t getId() const; + + /** + * Creates and returns a pointer to an instance of the type. Returns + * null if an instance could not be created for some reason. The + * pointer is returned as a generic pointer, but can be cast to the + * appropriate type. For example + * \code + * Group *g = static_cast Group::getClassTypeId().createInstance(); + * \endcode + * is a convoluted way of creating a new instance of a Group node. + */ + Typed* createInstance(); + + /** + * Creates and returns a pointer to an instance of the type + * associated with name. Returns null if an instance could not be + * created for some reason. If \c typeName does not correspond with a + * built-in type, it is looked for a shared object file which + * implements the requested type. + * + * \see ModuleManager + * \todo Library namespaces vs. shared object file names + */ + static Typed* createInstanceOfType(const std::string& typeName, + bool unloadable = true); + + /** + * Allow instances of this type to be network distributed if \true. + */ + void setDistributable(bool isDistributable); + + /** + * Returns \c true if instances of this type are allowed to be + * network distributed. + */ + bool isDistributable() const; + + /** + * Print out current type map via Avango Logging mechanism. + */ + static void dumpTypeMap(); + + private: + + /** + * Return index of the type in type map + */ + unsigned int getIndex() const; + + static bool isTypeRegistered(const std::string& typeName); + + static Type allocateNewType(bool isPublic, bool canCreate, + bool isAdaptor); + + static void registerNewType(const std::string& typeName, + Type parentType, Type newType, + Create* creator); + + static void initRegistry(); + + // make this class small, it will be a member of almost everything + union + { + struct { + uint32_t mIndex:29; // index into the type table + bool mIsPublic:1; // for quick checks without table lookup + bool mCanCreate:1; // for quick checks without table lookup + bool mIsAdaptor:1; // connection to Performer class hierarchy + } mStorage; + uint32_t mId; + } mTypeSpec; + + }; + + /** + * An Alias for Type::TypeList + */ + typedef Type::TypeList TypeList; + + InputStream& operator>>(InputStream& is, Type& value); + OutputStream& operator<<(OutputStream& os, const Type& value); + +} // namespace av + +/** + * Shortcut for object creation. + * \ingroup av + */ +#define AV_NEW(typeName) dynamic_cast(av::Type::createInstanceOfType(#typeName)) + +#endif // #if !defined(AV_TYPE_H) diff --git a/avango-core/include/avango/Typed.h b/avango-core/include/avango/Typed.h new file mode 100644 index 00000000..d21c846a --- /dev/null +++ b/avango-core/include/avango/Typed.h @@ -0,0 +1,222 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_TYPED_H) +#define AV_TYPED_H + +/** + * \file + * \ingroup av + */ + +// includes, system + +// includes, project + +#include +#include +#include + +namespace av +{ + + // types, exported (class, enum, struct, union, typedef) + + /** + * Abstract base class for all classes who wish to run under the + * runtime type system. The Typed class is an abstract base class. + * It provides runtime typing for derived classes. + * + * The Typed class provides a complex macro package which must + * be used by derived classes in order for runtime typing to work. + * + * \see AV_TYPED_DECLARE() + * + * \todo Use ::abort, ::exit, libfp::clean_exit or exceptions? + * \bug AV_TYPED_DECLAREd functions are undocumented + * + * \ingroup av + */ + class AV_DLL Typed + { + + public: + + /** + * Constructor + */ + Typed(); + + /** + * Destructor + */ + virtual ~Typed(); + + /** + * Type initialization. Must be called before instances of a typed + * class can be created. + */ + static void initClass(); + + /** + * Returns the type identifier for this class. + */ + static Type getClassTypeId(); + + /** + * Returns the type identifier for a specific instance. + * This method must be overloaded by derived classes, which should + * be done by calling AV_TYPED_DEFINE(). + */ + virtual Type getTypeId() const = 0; + + private: + + static Type sClassTypeId; + + }; + + // variables, exported (extern) + + // functions, inlined (inline) + + // functions, exported (extern) + +} + +// subclassing macros + +/** + * This macro must be called in the definition of all concrete classes + * derived from av::Typed. + * + * \ingroup av + */ +#define AV_TYPED_DECLARE() \ + public: \ + static void initClass(); \ + static ::av::Type getClassTypeId(); \ + static bool isTypeInitialized(); \ + ::av::Type getTypeId() const; \ +private: \ +static ::av::Type sClassTypeId + +/** + * This macro must be called in the definition of all abstract classes + * derived from av::Typed. + * + * \ingroup av + */ +#define AV_TYPED_DECLARE_ABSTRACT() \ + public: \ + static void initClass(); \ + static ::av::Type getClassTypeId(); \ + static bool isTypeInitialized(); \ +private: \ +static ::av::Type sClassTypeId + +/** + * This macro must be called at toplevel for all abstract classes + * derived from av::Typed. + * + * \pre AV_TYPED_DECLARE_ABSTRACT() must have been called prior to this. + * + * \ingroup av + */ +#define AV_TYPED_DEFINE_ABSTRACT(thisClass) \ + ::av::Type \ + thisClass::getClassTypeId() \ + { \ + AV_ASSERT(::av::Type::badType() != sClassTypeId); \ + return sClassTypeId; \ + } \ + bool \ + thisClass::isTypeInitialized() \ + { \ + return ::av::Type::badType() != sClassTypeId; \ + } \ + ::av::Type thisClass::sClassTypeId = ::av::Type::badType(); + +/** + * This macro must be called at toplevel for all concrete classes + * derived from av::Typed. + * + * \pre AV_TYPED_DECLARE() must have been called prior to this. + * + * \ingroup av + */ +#define AV_TYPED_DEFINE(thisClass) \ + ::av::Type \ + thisClass::getTypeId() const \ + { \ + AV_ASSERT(::av::Type::badType() != sClassTypeId); \ + return sClassTypeId; \ + } \ + AV_TYPED_DEFINE_ABSTRACT(thisClass) + +/** + * This macro must be called in DerivedClass::initClass() for all + * concrete classes derived from av::Typed. + * + * \pre AV_TYPED_DECLARE() must have been called prior to this. + * \pre All parent classes must have been initialized. You can ensure this + * by calling ParentClass::initClass(). + * + * \ingroup av + */ +#define AV_TYPED_INIT(parentClass, thisClass, create, isPublic) \ + do { \ + if (::av::Type::badType() == sClassTypeId) { \ + sClassTypeId = \ + ::av::Type::createType(::av::Type::getByName(#parentClass), \ + #thisClass, \ + create, \ + isPublic); \ + AV_ASSERT(::av::Type::badType() != sClassTypeId); \ + } \ + } while (0) + +/** + * This macro must be called in DerivedClass::initClass() for all + * abstract classes derived from av::Typed. + * + * \pre AV_TYPED_DECLARE_ABSTRACT() must have been called prior to this. + * \pre All parent classes must have been initialized. You can ensure this + * by calling ParentClass::initClass(). + * + * \ingroup av + */ +#define AV_TYPED_INIT_ABSTRACT(parentClass, thisClass, isPublic) \ + do { \ + if (::av::Type::badType() == sClassTypeId) { \ + sClassTypeId = \ + ::av::Type::createAbstractType(::av::Type::getByName(#parentClass), \ + #thisClass, \ + isPublic); \ + AV_ASSERT(::av::Type::badType() != sClassTypeId); \ + } \ + } while (0) + +#endif // #if !defined(AV_TYPED_H) diff --git a/avango-core/include/avango/WriteAction.h b/avango-core/include/avango/WriteAction.h new file mode 100644 index 00000000..f83397e0 --- /dev/null +++ b/avango-core/include/avango/WriteAction.h @@ -0,0 +1,147 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_WRITEACTION_H) +#define AV_WRITEACTION_H + +/** + * \file + * \ingroup av + */ + +// includes, system + +#include +#include + +// includes, project + +#include +#include + +namespace av +{ + + class Base; + + // types, exported (class, enum, struct, union, typedef) + + /** + * Write node hierarchies to a file. + * \ingroup av + */ + class AV_DLL WriteAction : public Action + { + + AV_BASE_DECLARE(); + + public: + + /** + * Constructor + */ + WriteAction(); + + /** + * Construct WriteAction and set file name. + */ + WriteAction(const std::string& name); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~WriteAction(); + + public: + + /** + * Sets the file name. + */ + void setFileName(const std::string& name); + + + /** + * Returns the output stream associated to the WriteAction. + * Objects written to the stream actually go into the file associated + * associated with the WriteAction. + */ + OutputStream& getStream(); + + /** + * Returns the object id of the object referenced by obj if valid, + * "null" otherwise. A new object id is created on demand. + */ + std::string lookupObjectId(Link obj); + + /** + * Returns \c true if \c obj has been written out to the current + * file. + */ + bool isObjectWritten(Link obj); + + /** + * Switch for writing in binary mode. + */ + void enableBinary(bool bin); + + /** + * Return \true if we are writing in binary mode. + */ + bool isBinaryEnabled(); + + // inherited from Action + + /* virtual */ void apply(Link node); + /* virtual */ void traverse(Link node); + + private: + + std::string getNewId(); + std::string depthIndent(); + + typedef std::map, std::string, std::less > > + BaseStringMap; + + BaseStringMap mIdMap; + + int mIdCounter; + int mBinary; + int mTravDepth; + std::string mName; + OutputStream mOutStream; + + }; + + // variables, exported (extern) + + // functions, inlined (inline) + + // functions, exported (extern) + +} + +#endif // #if !defined(AV_WRITEACTION_H) diff --git a/avango-core/include/avango/logging/Appender.h b/avango-core/include/avango/logging/Appender.h new file mode 100644 index 00000000..b5e787cc --- /dev/null +++ b/avango-core/include/avango/logging/Appender.h @@ -0,0 +1,67 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_APPENDER_H) +#define AVANGO_LOGGING_APPENDER_H + +// includes, system + +// includes, project +#include + +namespace av +{ + + namespace logging + { + + class LoggingEvent; + + /** + * Appender abstract base class. + * Appenders perform output processing of logging events. + */ + class AV_DLL Appender + { + + public: + + /** + * Process given logging event. + * This function is usually called by the logger. + */ + virtual void doAppend(LoggingEvent& event) = 0; + + protected: + + virtual ~Appender() {} + + }; + + } // namespace logging + +} // namespace av + +#endif // #if !defined(AVANGO_LOGGING_APPENDER_H) diff --git a/avango-core/include/avango/logging/Config.h b/avango-core/include/avango/logging/Config.h new file mode 100644 index 00000000..59bcc3ec --- /dev/null +++ b/avango-core/include/avango/logging/Config.h @@ -0,0 +1,46 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_CONFIG_H) +#define AVANGO_LOGGING_CONFIG_H + +/** + * \defgroup av_logging Avango Logging Library + */ + +/** + * \file + * \ingroup av_logging + */ + +/** + * \namespace av::logging + * Avango Logging Library + * + * \ingroup av_logging + */ + +#endif // #if !defined(AVANGO_LOGGING_CONFIG_H) + diff --git a/avango-core/include/avango/logging/ConsoleAppender.h b/avango-core/include/avango/logging/ConsoleAppender.h new file mode 100644 index 00000000..52006126 --- /dev/null +++ b/avango-core/include/avango/logging/ConsoleAppender.h @@ -0,0 +1,72 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_CONSOLEAPPENDER_H) +#define AVANGO_LOGGING_CONSOLEAPPENDER_H + +// includes, system + +// includes, project + +#include +#include +#include + + +namespace av +{ + + namespace logging + { + + /** + * Appender for printing log messages to std::clog. + * ConsoleAppender is a singleton. + * + * \todo Make it thread-safe + */ + + class AV_DLL ConsoleAppender : public Appender + { + + //friend class Singleton; + + public: + + /* virtual */ void doAppend(LoggingEvent& event); + ConsoleAppender() {} + virtual ~ConsoleAppender() {} + protected: + + + }; + typedef Singleton ConsoleAppenderInstance; + + } // namespace logging + +} // namespace av + +#endif // #if !defined(AVANGO_LOGGING_CONSOLEAPPENDER_H) + diff --git a/avango-core/include/avango/logging/FileAppender.h b/avango-core/include/avango/logging/FileAppender.h new file mode 100644 index 00000000..db32f66c --- /dev/null +++ b/avango-core/include/avango/logging/FileAppender.h @@ -0,0 +1,84 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_FILEAPPENDER_H) +#define AVANGO_LOGGING_FILEAPPENDER_H + +// includes, system + +#include +#include + +// includes, project + +#include +#include + +namespace av +{ + + namespace logging + { + + /** + * Appender for printing log messages to a file. + * + * \todo Error handling + * \todo Make it thread-safe + */ + class AV_DLL FileAppender : public Appender + { + + public: + + /** + * Create a file appender which logs to filename. + */ + FileAppender(const std::string& filename); + + /** + * Destructor + */ + virtual ~FileAppender(); + + /** + * Returns the filename of the file we are logging to. + */ + const std::string& getFilename() const; + + virtual void doAppend(LoggingEvent& event); + + private: + + const std::string mFilename; + std::ofstream mLogFile; + + }; + + } // namespace logging + +} // namespace av + +#endif // #if !defined(AVANGO_LOGGING_FILEAPPENDER_H) diff --git a/avango-core/include/avango/logging/Level.h b/avango-core/include/avango/logging/Level.h new file mode 100644 index 00000000..3c090b4f --- /dev/null +++ b/avango-core/include/avango/logging/Level.h @@ -0,0 +1,91 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// $Id + +#if !defined(AVANGO_LOGGING_LEVEL_H) +#define AVANGO_LOGGING_LEVEL_H + + +#if defined(_WIN32) + // MS VS 8 seems to define ERROR, which replaces the ERROR constant in the enum with a 0. + #if defined(ERROR) + #undef ERROR + #endif +#endif // _WIN32 + +/** + * \file + * \ingroup av_logging + */ + +// includes, system + +#include + +// includes, project +#include + +namespace av +{ + namespace logging + { + + // types, exported (class, enum, struct, union, typedef) + + /** + * Avango log levels. + * + * \ingroup av_logging + */ + + enum Level + { + FATAL, ///< Severe error that will lead to an application abort. + ERROR, ///< Severe error that still allows the application to continue. + WARN, ///< Potentially harmful situtation. + INFO, ///< Informational message that highlights the process of the application. + DEBUG, ///< Useful debugging information. + TRACE ///< Application tracing that may disturb even in debug level. + }; + + // variables, exported (extern) + + // functions, inlined (inline) + + // functions, exported (extern) + + /** + * Avango log level to string conversion + * + * \ingroup av_logging + */ + AV_DLL const std::string& levelToString(Level level); + + } // namespace logging + +} // namespace av + +#endif // #if !defined(AVANGO_LOGGING_LEVEL_H) diff --git a/avango-core/include/avango/logging/Logger.h b/avango-core/include/avango/logging/Logger.h new file mode 100644 index 00000000..289c051e --- /dev/null +++ b/avango-core/include/avango/logging/Logger.h @@ -0,0 +1,424 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_LOGGER_H) +#define AVANGO_LOGGING_LOGGER_H + +/** + * \file + * \ingroup av_logging + */ + +// includes, system + +#include +#include +#include + +#include +#include +#include +#include + +// includes, project + +#include +#include +#include +#include +#include + +namespace av +{ + namespace logging + { + + class Appender; + class LoggingEvent; + + // types, exported (class, enum, struct, union, typedef) + + /** + * Hierarchical logging facility. + * + * Loggers are hierarchically sorted by their names with "::" as divider. + * + * \ingroup av_logging + */ + class Logger + { + + public: + + friend class LoggerManager; + friend class Stream; + + /** + * A stream attached to a specific logger with a fixed log + * level which is assigned to messages passed to the stream. + * \todo Make it thread-safe. + */ + class Stream + { + + friend class Logger; + + public: + + /** + * Create logger stream for a specific logger and log level + * + * \param logger Target logger for all messages passed to the stream + * \param level log level of the stream. + */ + AV_DLL Stream(Logger& logger, Level level); + + /** + * Destructor. + * Flushes the Stream. + */ + AV_DLL ~Stream(); + + /** + * Messages passed with << to the Stream are logged to the + * underlying logger with the current log level. + */ + template Stream& operator<<(const T& t); + + /** + * Pass values for parameters to Stream. These are used for + * %-style placeholders with boost::format syntax. + * + * operator<<() calls are not allowed after operator,(). + * + * \note not using boost::format syntax because of operator%-precedence + */ + template Stream& operator,(const T& t); + + /** + * Flushes the Stream. + */ + AV_DLL void flush(); + + private: + + /** + * Made private to prevent copy construction + */ + Stream(const Stream&); + + /** + * Made private to prevent assignment + */ + Stream& operator=(const Stream&); + + Logger& mLogger; + Level mLevel; + std::ostringstream mBuf; + boost::format mFormatter; + }; + + /** + * Create specific logger instance with the given name + * + * \param name Name in logger hierarchy, usually the class name, e.g. "av::Logger". + */ + AV_DLL Logger(const std::string& name = "", Level level = INFO); + + /** + * Return specific logger with the given name. + * If it does not yet exist, it is automatically created. + * + * \param name Name in logger hierarchy, usually the class name, e.g. "av::Logger". + * + * \throw std::invalid_argument if the logger name contains ':::' or ends with '::' + */ + AV_DLL static Logger& getLogger(const std::string& name); + + /** + * Return the root logger, which gets all messages. + */ + AV_DLL static Logger& getRootLogger(); + + /** + * Use Logger as functor to stream message into log. + * This produces slightly more overhead than calling log() directly. + */ + AV_DLL Stream operator()(Level level); + + /** + * Log a message with given log level. + * \param level Log level of this message. + * \param msg Message to log. + */ + AV_DLL void log(Level level, const std::string& msg); + + /** + * Return stream for loging messages with fatal level. + */ + AV_DLL Stream fatal(); + + /** + * Log a message with fatal level + * \param msg Message to log. + */ + AV_DLL void fatal(const std::string& msg); + + /** + * Return stream for loging messages with error level. + */ + AV_DLL Stream error(); + + /** + * Log a message with error level + * \param msg Message to log. + */ + AV_DLL void error(const std::string& msg); + + /** + * Return stream for loging messages with warn level. + */ + AV_DLL Stream warn(); + + /** + * Log a message with warn level + * \param msg Message to log. + */ + AV_DLL void warn(const std::string& msg); + + /** + * Return stream for loging messages with info level. + */ + AV_DLL Stream info(); + + /** + * Log a message with info level + * \param msg Message to log. + */ + AV_DLL void info(const std::string& msg); + + /** + * Return stream for loging messages with debug level. + */ + AV_DLL Stream debug(); + + /** + * Log a message with debug level + * \param msg Message to log. + */ + AV_DLL void debug(const std::string& msg); + + /** + * Return stream for loging messages with trace level. + */ + AV_DLL Stream trace(); + + /** + * Log a message with trace level + * \param msg Message to log. + */ + AV_DLL void trace(const std::string& msg); + + /** + * Returns the name of this logger. + */ + AV_DLL const std::string& getName() const; + + /** + * Returns true if the logger has a parent logger. + */ + AV_DLL bool hasParent() const; + + /** + * Returns the parent logger of this logger. + * \throw std::logic_error If the logger has no parents (which means it is the root logger). + */ + AV_DLL Logger& getParent(); + + /** + * Returns the parent logger of this logger. + * \throw std::logic_error If the logger has no parents (which means it is the root logger). + */ + AV_DLL const Logger& getParent() const; + + /** + * Get level of this logger. Only messages >= this level are logged + */ + AV_DLL Level getLevel() const; + + /** + * Set level of this logger. Only messages >= level are logged + */ + AV_DLL void setLevel(Level level); + + /** + * Adds an appender to this logger. + * If it has been added before, nothing will happen. + */ + AV_DLL void addAppender(boost::shared_ptr appender); + + /** + * Adds the console appender to this logger. + * If it has been added before, nothing will happen. + */ + AV_DLL void addConsoleAppender(); + + /** + * Removes an appender from this logger. + * If it has not been added before, nothing will happen. + */ + AV_DLL void removeAppender(boost::shared_ptr appender); + + /** + * Removes the console appender from this logger. + * If it has not been added before, nothing will happen. + */ + AV_DLL void removeConsoleAppender(); + + /** + * Removes all appenders from this logger. + */ + AV_DLL void removeAllAppenders(); + + /** + * Check if this logger (or one of its parents) has at least one appender + */ + AV_DLL bool isActive(Level level) const; + + /** + * Functor used to compare two boost::shared_ptrs + */ + struct AV_DLL compareSharedPtrs + { + bool operator()(const boost::shared_ptr p1, const boost::shared_ptr p2) const + { + return p1.get() < p2.get(); + } + }; + + /** + * Returns a list of already added appenders + */ + AV_DLL const std::set, compareSharedPtrs >& getAppenders() const; + + private: + + /** + * Made private to prevent copy construction + */ + Logger(const Logger&); + + /** + * Made private to prevent assignment + */ + Logger& operator=(const Logger&); + + /** + * Log a LoggingEvent created by ourselves or a child logger. + */ + void passMessage(LoggingEvent& event); + + /** + * Set the parent logger. + * Used only by LoggerManager. + */ + void setParent(Logger* parent); + + std::string mName; + Level mLevel; + Logger* mParent; + std::set, compareSharedPtrs > mAppenders; + boost::mutex mAppenderMutex; + }; + + // variables, exported (extern) + + template inline Logger::Stream&Logger::Stream::operator<<(const T& t) + { + if (mLevel <= mLogger.mLevel) { + AV_ASSERT(0 == mFormatter.size()); + mBuf << t; + } + return *this; + } + + template inline Logger::Stream& + Logger::Stream::operator,(const T& t) + { + if (mLevel <= mLogger.mLevel) + { + if (0 == mFormatter.size()) + { + mFormatter.parse(mBuf.str()); + } + + mFormatter % t; + } + return *this; + } + + } // namespace logging + + // convenience definitions + + /** + * Convenience definition, shorthand for logging::Logger. + * \ingroup av_logging + */ + typedef logging::Logger Logger; + + /** + * Convenience definition, shorthand for Logger::getLogger. + * \ingroup av_logging + */ + AV_DLL inline Logger& getLogger(const std::string& name) + { + return logging::LoggerManagerInstance::get().getLogger(name); + } + + /** + * Convenience definition, shorthand for Logger::getRootLogger. + * \ingroup av_logging + */ + AV_DLL inline Logger& getRootLogger() + { + return logging::LoggerManagerInstance::get().getRootLogger(); + } + +} // namespace av + +#ifdef TRACE_LOGGING +#define LOG_TRACE(trace_logger)\ + (trace_logger).trace() +#else +#define LOG_TRACE(trace_logger)\ + if (false) (trace_logger).trace() +#endif + +#define AVANGO_LOG(logger, level, message)\ + if ((level <= AVANGO_LOG_LEVEL) && (logger.isActive(level)))\ + logger.log(level, message); + +#endif // #if !defined(AVANGO_LOGGING_LOGGER_H) diff --git a/avango-core/include/avango/logging/LoggerManager.h b/avango-core/include/avango/logging/LoggerManager.h new file mode 100644 index 00000000..25af7053 --- /dev/null +++ b/avango-core/include/avango/logging/LoggerManager.h @@ -0,0 +1,88 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_LOGGERMANAGER_H) +#define AVANGO_LOGGING_LOGGERMANAGER_H + +#include +#include + +#include +#include + +namespace av +{ + namespace logging + { + class Logger; + //class LoggerManager; + + /** + * Responsible for creating and destroying logger instancies. + */ + + class AV_DLL LoggerManager/* : public SingletonThreadSafe*/ + { + + //friend class SingletonThreadSafe;//; + + public: + + /** + * Return the root logger, which gets all messages. + */ + Logger& getRootLogger(); + + /** + * Return specific logger with the given name. + * If it does not yet exist, it is automatically created. + * + * \param name Name in logger hierarchy, usually the class name, e.g. "av::Logger". + * + * \throw std::invalid_argument if the logger name contains ':::' or ends with '::' + */ + Logger& getLogger(const std::string& name); + + LoggerManager(); + virtual ~LoggerManager(); + LoggerManager& operator=(const LoggerManager&); + + private: + typedef std::map LoggerMap; + LoggerMap& getLoggerMap(); + + boost::mutex mLoggerMapMutex; + Logger* mRootLogger; + LoggerMap mLoggerMap; + + }; + + typedef Singleton LoggerManagerInstance; + + } //namespace logging + +} // namespace av + +#endif // #if !defined(AVANGO_LOGGING_LOGGERMANAGER_H) diff --git a/avango-core/include/avango/logging/LoggingEvent.h b/avango-core/include/avango/logging/LoggingEvent.h new file mode 100644 index 00000000..290633b6 --- /dev/null +++ b/avango-core/include/avango/logging/LoggingEvent.h @@ -0,0 +1,101 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_LOGGINGEVENT_H) +#define AVANGO_LOGGING_LOGGINGEVENT_H + +// includes, system + +#include + +// includes, project + +#include +#include + +namespace av +{ + + namespace logging + { + + /** + * Internal representation of logging events. + * \todo Record process-id, thread-id etc. + */ + class AV_DLL LoggingEvent + { + + public: + + /** + * Constructor. + */ + LoggingEvent(Logger& logger, Level level, const std::string& msg); + + /** + * Destructor. + */ + ~LoggingEvent(); + + /** + * Get originating logger of this logging event. + */ + Logger& getLogger(); + + /** + * Get message of this logging event. + */ + const std::string& getMessage() const; + + /** + * Get timestamp of this logging event (seconds since 1970-01-01 GMT). + */ + double getTimeStamp() const; + + /** + * Get level of this logging event. + */ + Level getLevel(); + + /** + * Get formatted string of this logging event. + */ + std::string getFormattedString(); + + private: + + Logger& mLogger; + std::string mMsg; + Level mLevel; + double mTimeStamp; + + }; + + } // namespace logging + +} // namespace av + +#endif // #if !defined(AV_LOGGINGEVENT_H) diff --git a/avango-core/include/avango/logging/SConscript b/avango-core/include/avango/logging/SConscript new file mode 100644 index 00000000..743301a3 --- /dev/null +++ b/avango-core/include/avango/logging/SConscript @@ -0,0 +1,38 @@ +# -*- Mode:Python -*- + +########################################################################## +# # +# This file is part of AVANGO. # +# # +# Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der # +# angewandten Forschung (FhG), Munich, Germany. # +# # +# AVANGO is free software: you can redistribute it and/or modify # +# it under the terms of the GNU Lesser General Public License as # +# published by the Free Software Foundation, version 3. # +# # +# AVANGO is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU Lesser General Public # +# License along with AVANGO. If not, see . # +# # +########################################################################## + +import avango.build + +headers = Split(''' + Appender.h + ConsoleAppender.h + Config.h + FileAppender.h + Level.h + Logger.h + LoggingEvent.h + LoggerManager.h + StreamAppender.h + ''') + +Alias('install', Install(avango.build.get_include_path('avango/logging'), headers)) diff --git a/avango-core/include/avango/logging/StreamAppender.h b/avango-core/include/avango/logging/StreamAppender.h new file mode 100644 index 00000000..b051d4db --- /dev/null +++ b/avango-core/include/avango/logging/StreamAppender.h @@ -0,0 +1,75 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_LOGGING_STREAMAPPENDER_H) +#define AVANGO_LOGGING_STREAMAPPENDER_H + +// includes, system + +#include + +// includes, project + +#include +#include + +namespace av +{ + + namespace logging + { + + /** + * Appender for printing log messages to a stream. + * \todo Make it thread-safe + */ + class AV_DLL StreamAppender : public Appender + { + + public: + + /** + * Constructor made private to prevent multiple instantiation. + */ + StreamAppender(std::ostream& os); + + /** + * Destructor + */ + virtual ~StreamAppender(); + + /* virtual */ void doAppend(LoggingEvent& event); + + private: + + std::ostream &mStream; + + }; + + } // namespace logging + +} // namespace av + +#endif // #if !defined(AVANGO_LOGGING_STREAMAPPENDER_H) diff --git a/avango-core/include/avango/stdint_replacement.h b/avango-core/include/avango/stdint_replacement.h new file mode 100644 index 00000000..c17dd142 --- /dev/null +++ b/avango-core/include/avango/stdint_replacement.h @@ -0,0 +1,44 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_STDINT_REPLACEMENT_H) +#define AV_STDINT_REPLACEMENT_H + +#if !defined(_MSC_VER) +#error "Typedefs in this header are supposed to be used with Visual Studio" +#endif + +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef signed __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +typedef unsigned int uint; + +#endif // if !defined(AV_STDINT_REPLACEMENT_H) diff --git a/avango-core/include/avango/windows_specific.h b/avango-core/include/avango/windows_specific.h new file mode 100644 index 00000000..51ab9294 --- /dev/null +++ b/avango-core/include/avango/windows_specific.h @@ -0,0 +1,44 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_WINDOWS_SPECIFIC_H) +#define AV_WINDOWS_SPECIFIC_H + +/** + * \file + * \ingroup av + */ + +#if defined(_MSC_VER) + #if defined(AV_LIBRARY) + #define AV_DLL __declspec( dllexport ) + #else + #define AV_DLL __declspec( dllimport ) + #endif +#else + #define AV_DLL +#endif // #if defined(_MSC_VER) + +#endif // #if !defined(AV_WINDOWS_SPECIFIC_H) diff --git a/avango-core/src/avango/Init.cpp b/avango-core/src/avango/Init.cpp new file mode 100644 index 00000000..9069a95b --- /dev/null +++ b/avango-core/src/avango/Init.cpp @@ -0,0 +1,52 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::Init")); +} + +AV_TYPED_DEFINE_ABSTRACT(av::Init); + +/* static */ void +av::Init::initClass() +{ + if (!isTypeInitialized()) + { + av::Type::init(); + av::initStandardFields(); + + av::TimeSensor::initClass(); + + AV_TYPED_INIT_ABSTRACT(av::Type::badType(), "av::Init", true); + } +} diff --git a/avango-core/src/avango/actions/Action.cpp b/avango-core/src/avango/actions/Action.cpp new file mode 100644 index 00000000..2727d1b0 --- /dev/null +++ b/avango-core/src/avango/actions/Action.cpp @@ -0,0 +1,85 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include "avango/Action.h" + +// includes, system + +#include + +// includes, project + +#include + +// internal unnamed namespace + +namespace +{ + // types, internal + + // variables, internal + + av::Logger& logger(av::getLogger("av::Action")); + + // functions, internal + +} // namespace + +// variables, exported + +// functions, exported + +AV_BASE_DEFINE(av::Action); + +av::Action::Action() +{} + +/* virtual */ +av::Action::~Action() +{} + +/* static */ void +av::Action::initClass() +{ + if (!isTypeInitialized()) { + Base::initClass(); + AV_BASE_INIT_ABSTRACT(av::Base, av::Action, true); + + } +} + +/* virtual */ void +av::Action::apply(Link node) +{ + traverse(node); +} + +/* virtual */ void +av::Action::traverse(Link node) +{ + node->doAction(*this); +} diff --git a/avango-core/src/avango/actions/WriteAction.cpp b/avango-core/src/avango/actions/WriteAction.cpp new file mode 100644 index 00000000..f35678e7 --- /dev/null +++ b/avango-core/src/avango/actions/WriteAction.cpp @@ -0,0 +1,209 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include "avango/WriteAction.h" + +// includes, system + +#include +#include +#include + +// includes, project + +#include + +// internal unnamed namespace + +namespace +{ + // types, internal + + // variables, internal + + av::Logger& logger(av::getLogger("av::WriteAction")); + + const int ID_COUNTER_INIT_VALUE = 0; + const int BINARY_INIT_VALUE = true; + + const int DEPTH_INDENT_SPACES = 4; + +// functions, internal + +} // namespace + +AV_BASE_DEFINE(av::WriteAction) +; + +av::WriteAction::WriteAction() : + mIdCounter(ID_COUNTER_INIT_VALUE), mBinary(BINARY_INIT_VALUE) +{ +} + +av::WriteAction::WriteAction(const std::string& fileName) : + mIdCounter(ID_COUNTER_INIT_VALUE), mBinary(BINARY_INIT_VALUE) +{ + setFileName(fileName); +} + +/* virtual */ +av::WriteAction::~WriteAction() +{ +} + +void av::WriteAction::initClass() +{ + if (!isTypeInitialized()) + { + av::Action::initClass(); + + AV_BASE_INIT(av::Action, av::WriteAction, true); + } +} + +void av::WriteAction::setFileName(const std::string& fileName) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("setFileName(): file name is '%1%'") % mName)) + mName = fileName; +} + +/* virtual */void av::WriteAction::apply(av::Link node) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("apply(): writing to ''%1%'") % mName)) + + std::ofstream file(mName.c_str()); + + if (file.fail()) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("apply(): can't open file ''%1%'") % mName)) + return; + } + + mIdMap.clear(); + mIdCounter = 0; + mOutStream = file; + mOutStream.setWriteAction(this); + mOutStream.enableBinary(mBinary); + + mTravDepth = -1; + traverse(node); + + mIdMap.clear(); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("apply(): closing file ''%1%'") % mName)) +} + +/* virtual */void av::WriteAction::traverse(av::Link node) +{ + ++mTravDepth; + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("traverse(): %snode: 0x%x (%s)") + % depthIndent() % node.getPtr() % node->getTypeId().getName().c_str())) + + if (node.isValid()) + { + node->doWriteAction(*this); + } + --mTravDepth; +} + +void av::WriteAction::enableBinary(bool bin) +{ + mBinary = bin; +} + +bool av::WriteAction::isBinaryEnabled() +{ + return mBinary; +} + +av::OutputStream& av::WriteAction::getStream() +{ + return mOutStream; +} + +std::string av::WriteAction::getNewId() +{ + std::ostringstream new_id_string; + + new_id_string << "object" << mIdCounter; + mIdCounter++; + return new_id_string.str(); +} + +std::string av::WriteAction::lookupObjectId(av::Link obj) +{ + if (!obj.isValid()) + { + return "null"; + } + + BaseStringMap::iterator object_id = mIdMap.find(obj); + if (object_id != mIdMap.end()) + { + return (*object_id).second; + } + else + { + std::string id = getNewId(); + mIdMap.insert(BaseStringMap::value_type(obj, id)); + return id; + } +} + +bool av::WriteAction::isObjectWritten(av::Link obj) +{ + if (!obj.isValid()) + { + throw std::invalid_argument("av::Link is not valid"); + } + + BaseStringMap::iterator object_id = mIdMap.find(obj); + if (object_id != mIdMap.end()) + { + return true; + } + else + { + std::string id = getNewId(); + mIdMap.insert(BaseStringMap::value_type(obj, id)); + return false; + } +} + +std::string av::WriteAction::depthIndent() +{ + if (mTravDepth == -1) + { + return ""; + } + + // create a string with mTravDepth * DEPTH_INDENT_SPACES spaces + std::string indent_string(mTravDepth * DEPTH_INDENT_SPACES, ' '); + + return indent_string; +} diff --git a/avango-core/src/avango/fields/Field.cpp b/avango-core/src/avango/fields/Field.cpp new file mode 100644 index 00000000..0c0bfb7d --- /dev/null +++ b/avango-core/src/avango/fields/Field.cpp @@ -0,0 +1,725 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::Field")); + + /// Helper class to make setting/unsetting bool values exception safe (RAII Idiom) + class SetBoolFlag + { + public: + SetBoolFlag(bool& value) : + mValueRef(value) + { + mValueRef = true; + } + ~SetBoolFlag() + { + mValueRef = false; + } + private: + bool& mValueRef; + }; + + bool defaultPushIsMulti = true; + bool defaultInputIsMulti = true; + +} // namespace + +AV_TYPED_DEFINE_ABSTRACT(av::Field); + +void +av::Field::setContainer(av::FieldContainer* c, unsigned int i, bool owned) +{ + AV_ASSERT(c); + + mContainer = c; + mIndex = i; + mFlags.owned = owned; +} + +av::FieldContainer* +av::Field::getContainer() const +{ + AV_ASSERT(mContainer); + + return mContainer; +} + +bool +av::Field::isBound() const +{ + return (mContainer != 0); +} + +unsigned int +av::Field::getIndex() const +{ + return mIndex; +} + +av::Field* +av::Field::getConnectedField(unsigned int index) +{ + if (index >= mConnectedFrom.size()) + { + return 0; + } + + InputFieldsList::iterator listIter = mConnectedFrom.begin(); + std::advance(listIter, index); + return listIter->first; +} + +unsigned int +av::Field::getNumberOfConnectedFields() const +{ + return mConnectedFrom.size(); +} + +void +av::Field::enableDependency(bool on) +{ + mFlags.dependencyEnabled = on; +} + +bool +av::Field::dependencyEnabled() +{ + return mFlags.dependencyEnabled; +} + +void +av::Field::enableNotify(bool on) +{ + mFlags.notifyEnabled = on; +} + +bool +av::Field::notifyEnabled() +{ + return mFlags.notifyEnabled; +} + +void +av::Field::notify(Field* triggered_from) +{ +#if defined(AVANGO_DEBUG) + if (mFlags.hasNotified && !mAuditors.empty()) + { + SingleField* container_name = + dynamic_cast* >(getContainer()->getField("Name")); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("notify: " + "%1% . %2% of type <%3%.%4%> %5%-pushed, %6% auditor%7% was already notified.") + % (0 != container_name ? container_name->getValue() : "unnamed") + % getName() + % getContainer()->getTypeId().getName() + % getTypeId().getName() + % (mFlags.multiPush ? "multi" : "single") + % mAuditors.size() + % (1 != mAuditors.size() ? "s" : "") + )); + } +#endif + + if (mIsNotifying) + { + throw std::runtime_error("Field triggered while in on notify call. Possible loop."); + } + + if (mFlags.hasNotified && !mFlags.multiPush) + { + return; + } + + SetBoolFlag isNotifying(mIsNotifying); + + // copy and reference auditors while in notify because the connection topology may change + FieldPtrVec auditors; + auditors.reserve(mAuditors.size()); + std::copy(mAuditors.begin(), mAuditors.end(), std::back_inserter(auditors)); + + FieldPtrVec::const_iterator current; + FieldPtrVec::const_iterator past_of_end = auditors.end(); + for (current = auditors.begin(); current != past_of_end; ++current) + { + Field* to_field(*current); + + AV_ASSERT(to_field != 0); + + if (to_field != triggered_from) + { + to_field->setFieldChangeSource(connection); + to_field->pullValue(this); + } + } + + mFlags.hasNotified = true; +} + +void +av::Field::touch() +{ + fieldChanged(false); +} + +void +av::Field::reset() +{ + mFlags.touched = false; + mFlags.hasNotified = false; +} + +void +av::Field::dontWrite(bool on) +{ + mFlags.dontWrite = on; +} + +bool +av::Field::isWritable() const +{ + return !mFlags.dontWrite; +} + +void +av::Field::dontDistribute(bool on) +{ + mFlags.dontDistribute = on; +} + +void +av::Field::needsDistribution(bool on) +{ + mFlags.needsDistribution = on; +} + +bool +av::Field::needsDistribution() const +{ + return mFlags.needsDistribution; +} + +bool +av::Field::isDistributable() const +{ + return !mFlags.dontDistribute; +} + +bool +av::Field::isMultiPush () const +{ + return mFlags.multiPush; +} + +void +av::Field::setMultiPush (bool onoff) +{ + if (!onoff) + { + AVANGO_LOG(logger, logging::WARN, "Disabling multi-push on a field is deprecated."); + } + + mFlags.multiPush = onoff; +} + +bool +av::Field::isMultiInput () const +{ + return mFlags.multiInput; +} + +void +av::Field::setMultiInput (bool onoff) +{ + if (!onoff) + { + AVANGO_LOG(logger, logging::WARN, "Disabling multi-input on a field is deprecated."); + } + + mFlags.multiInput = onoff; +} + +bool +av::Field::isOwned() const +{ + return mFlags.owned; +} + +av::Field::Field() : + mContainer(0), + mIndex(0), + mIsNotifying(false), + mSrc(internal) +{ + mFlags.touched = false; + mFlags.notifyEnabled = true; + mFlags.dependencyEnabled = true; + mFlags.hasNotified = false; + mFlags.dontWrite = false; + mFlags.dontDistribute = false; + mFlags.needsDistribution = false; + mFlags.multiPush = defaultPushIsMulti; + mFlags.multiInput = defaultInputIsMulti; + mFlags.owned = false; +} + +const std::string& +av::Field::getName() const +{ + AV_ASSERT(mContainer != 0); + + return mContainer->getFieldName(mIndex); +} + +void +av::Field::fieldChanged(bool fromNet, Field* triggeredFrom) +{ + if (!mContainer) + { + return; + } + + if (!fromNet) + { + mFlags.needsDistribution = true; + } + + if (notifyEnabled()) + { + mContainer->fieldChanged(*this, fromNet); + notify(triggeredFrom); + ContainerPool::notifyFieldHasChanged(this); + setFieldChangeSource(fromNet ? net : internal); + } + + mFlags.touched = true; +} + + +void +av::Field::connectFrom(av::Field* field, bool dependent) +{ + if (!field) + { + throw std::invalid_argument("av::Field* field is 0"); + } + + // discard old connection + if (!mFlags.multiInput) + { + disconnect(); + } + + mConnectedFrom.push_back(std::make_pair(field, dependent)); + field->addAuditor(this); + + ContainerPool::notifyConnect(this); +} + +void +av::Field::disconnect() +{ + if (mConnectedFrom.empty()) + { + return; + } + + // prevent deletion if container is only referenced via field connections + Link container_ref(getContainer()); + + for (InputFieldsList::iterator list_iter = mConnectedFrom.begin(); + list_iter != mConnectedFrom.end(); + ++list_iter) + { + list_iter->first->removeAuditor(this); + } + + mConnectedFrom.clear(); + + // we can notice disconnects this way + touch(); + + ContainerPool::notifyDisconnect(this); +} + +namespace +{ + template class first_equal_to + { + typedef std::pair Pair; + A mValue; + + public: + + first_equal_to(const A& value) : + mValue(value) + { + } + + bool operator() (const Pair& x) + { + return x.first == mValue; + } + }; +} + +void +av::Field::disconnectFrom(av::Field* field) +{ + if (mConnectedFrom.empty()) + { + return; + } + + InputFieldsList::iterator field_iter = std::find_if(mConnectedFrom.begin(), + mConnectedFrom.end(), + first_equal_to(field)); + if (field_iter == mConnectedFrom.end()) + { + return; + } + + // prevent deletion if container is only referenced via field connections + Link container_ref(getContainer()); + + field_iter->first->removeAuditor(this); + mConnectedFrom.erase(field_iter); + + // we can notice disconnects this way + touch(); + + ContainerPool::notifyDisconnect(this); +} + +const av::Field::FieldPtrSet& +av::Field::getAuditors() const +{ + return mAuditors; +} + +void +av::Field::disconnectAuditors() +{ + while (!mAuditors.empty()) + { + (*mAuditors.begin())->disconnectFrom(this); + } +} + +void +av::Field::addAuditor(av::Field* field) +{ + AV_ASSERT(field); + + field->getContainer()->reference(); + mAuditors.insert(field); + field->pullValue(this); +} + +void +av::Field::removeAuditor(av::Field* field) +{ + AV_ASSERT(field); + + mAuditors.erase(field); + field->getContainer()->unreference(); +} + +av::Field::FieldChangeSource +av::Field::getFieldChangeSource() const +{ + return mSrc; +} + +void +av::Field::setFieldChangeSource(FieldChangeSource src) +{ + mSrc = src; +} + +void +av::Field::bind(av::FieldContainer* container, const std::string& name, bool owned) +{ + AV_ASSERT(container); + + if (isBound()) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("bind: %1%.%2% already bound") + % (container ? container->getTypeId().getName() : "null-pointer" ) + % name)); + return; + } + + unsigned int index = container->addField(this, name); + setContainer(container, index, owned); +} + +void +av::Field::unbind() +{ + AV_ASSERT(mContainer); + mContainer->removeField(mIndex); + mContainer=0; + mIndex=0; +} + + +/* vitual */ void +av::Field::clear() +{} + +/* virtual */ +av::Field::~Field() +{ + disconnectAuditors(); + AV_ASSERT(mAuditors.size() == 0); + + //disconnectAllFields is not needed, since this field is referenced by the auditor field. In case this + //assertion should be triggered, a fault in the avango field mechanism exists + AV_ASSERT(mConnectedFrom.size() == 0); + +} + +void +av::Field::initClass() +{ + if (!isTypeInitialized()) + { + AV_TYPED_INIT_ABSTRACT(av::Typed, av::Field, true); + } +} + +av::Type +av::Field::registerType(const std::string& classname, + const std::string& parentname, + av::Create* creator) +{ +#if defined(AVANGO_DEBUG) + AVANGO_LOG(logger, logging::DEBUG, boost::str(boost::format("registerType: registration request for type '%1%' with parent type '%2%'.") + % classname + % parentname + )); +#endif + + Type type (Type::getByName(classname)); + + if (Type::badType() != type) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("registerType: type '%1%' already registered, returning '%2%'!") + % classname + % type.getName() + )); + return type; + } + + Type parent; + if (!parentname.empty()) + { + parent = Type::getByName(parentname); + if (Type::badType() == parent) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("registerType: parent type '%1%' of type '%2%' doesn't exist, returning '%3%'!") + % parentname + % classname + % Type::badType().getName() + )); + return Type::badType(); + } + } + else + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("registerType: setting parent type '%1%' of type '%2%' to '%3%'!") + % parentname + % classname + % Type::badType().getName() + )); + parent = Type::badType(); + } + + type = Type::createType(parent, classname, creator, true); + +#if defined(AVANGO_DEBUG) + AVANGO_LOG(logger, logging::DEBUG, boost::str(boost::format("registerType: created type '%1%' (id: %2%, parent: '%3%').") + % type.getName() + % type.getId() + % type.getParent().getName() + )); +#endif + return type; +} + +av::InputStream& +av::operator>>(av::InputStream& is, av::Field* field) +{ + field->read(is); + return is; +} + +av::OutputStream& +av::operator<<(av::OutputStream& os, const av::Field* field) +{ + const_cast(field)->write(os); + return os; +} + +void +av::Field::writeConnection(av::OutputStream& os) +{ + Field* connected_field = getConnectedField(); + + if (!connected_field) + { + (std::ostream&) os << 'N'; + return; + } + + (std::ostream&) os << 'C'; + + uint32_t index = connected_field->getIndex(); + + os.write((char*) &index, sizeof(index)); + + if (os.getWriteAction()->isObjectWritten(connected_field->getContainer())) + { + // object is alraedy in file, only add reference + (std::ostream&) os << 'R'; + + os << os.getWriteAction()->lookupObjectId(connected_field->getContainer()); + } + else + { + // object is not written, write it. + (std::ostream&) os << 'O'; + + // this will recurse write actions on base links + os.getWriteAction()->traverse(connected_field->getContainer()); + } +} + +void +av::Field::readConnection(av::InputStream& is) +{ + char con_flag; + + (std::istream&) is >> con_flag; + + if (con_flag != 'C') + { + return; + } + + uint32_t index = 0; + + is.read((char*) &index, sizeof(index)); + + av::Base* from_base = 0; + char reference_flag; + + (std::istream&) is >> reference_flag; + + if (reference_flag == 'R') { + // object is already there, just connect + std::string obj_id; + + is >> obj_id; + + from_base = is.getReader()->lookupObject(obj_id); + } else { + // object is new, load it + from_base = is.getReader()->readObject(is); + } + + // make connection + if (from_base && + from_base->getTypeId().isOfType(FieldContainer::getClassTypeId())) + { + FieldContainer* fc = (FieldContainer*) from_base; + Field* from_field = fc->getField(index); + + this->connectFrom(from_field); + } + else + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("read: can't resolve field connection for type '%1%'!") + % (from_base ? from_base->getTypeId().getName() : "unnamed at 0x0") + )); + } +} + +void +av::Field::evaluateDependencies(void) +{ + if ( (mConnectedFrom.empty()) || (!dependencyEnabled()) ) + { + return; + } + + // reference all connected containers as connections may change dynamically + std::list > connected_from_containers; + + for (Field::InputFieldsList::iterator from_field_it = mConnectedFrom.begin(); + from_field_it != mConnectedFrom.end(); ++from_field_it) + { + + if (from_field_it->second) + { + connected_from_containers.push_back(from_field_it->first->getContainer()); + } + } + + //Currently, the input field iterator can be invalidated, in case the user calls connect_from in an evaluate + //Therefore, all fields are first copied into a list and then evaluated + while (!connected_from_containers.empty()) + { + connected_from_containers.front()->callEvaluate(); + connected_from_containers.pop_front(); + } + +} diff --git a/avango-core/src/avango/fields/MultiField.cpp b/avango-core/src/avango/fields/MultiField.cpp new file mode 100644 index 00000000..58610f34 --- /dev/null +++ b/avango-core/src/avango/fields/MultiField.cpp @@ -0,0 +1,390 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +namespace +{ + + template + bool fieldHasType(av::Field* field) + { + AV_ASSERT(field); + return field->getTypeId().isOfType(av::MultiField::getClassTypeId()); + } + + template + std::vector convertFieldValue(av::Field* field) + { + AV_ASSERT(field); + av::MultiField* from_multi_field = dynamic_cast*>(field); + AV_ASSERT(from_multi_field); + const std::vector& inVec = from_multi_field->getValue(); + std::vector outVec(inVec.size()); + + std::copy(inVec.begin(), inVec.end(), outVec.begin()); + return outVec; + } + +} + +template<> +void av::MultiField::pullValueImpl(av::Field* fromField) +{ + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::MultiField::pullValueImpl(av::Field* fromField) +{ + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } else + { + throw std::invalid_argument( "pullValue: type mismatch. " + getTypeId().getName() + + " <--> " + fromField->getTypeId().getName()); + } +} + +template<> +void av::MultiField::pullValueImpl(av::Field* fromField) +{ + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::MultiField::pullValueImpl(av::Field* fromField) +{ + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::MultiField::pullValueImpl(av::Field* fromField) +{ + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::MultiField::pullValueImpl(av::Field* fromField) +{ + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::MultiField::pullValueImpl(av::Field* fromField) +{ + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + +template<> void +av::MultiField::push(av::Msg& msg) +{ + getValue(); + av_pushMsg(msg, mValue); +} + +template<> void +av::MultiField::pop(av::Msg& msg) +{ + av_popMsg(msg, mValue); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); +} + +template<> void +av::MultiField::push(av::Msg& msg) +{ + getValue(); + av_pushMsg(msg, mValue); +} + +template<> void +av::MultiField::pop(av::Msg& msg) +{ + av_popMsg(msg, mValue); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); +} + +template<> void +av::MultiField::push(av::Msg& msg) +{ + getValue(); + av_pushMsg(msg, mValue); +} + +template<> void +av::MultiField::pop(av::Msg& msg) +{ + av_popMsg(msg, mValue); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); +} + +template<> void +av::MultiField::push(av::Msg& msg) +{ + getValue(); + av_pushMsg(msg, mValue); +} + +template<> void +av::MultiField::pop(av::Msg& msg) +{ + av_popMsg(msg, mValue); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); +} + +template<> void +av::MultiField::push(av::Msg& msg) +{ + getValue(); + av_pushMsg(msg, mValue); +} + +template<> void +av::MultiField::pop(av::Msg& msg) +{ + av_popMsg(msg, mValue); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); +} + +template<> void +av::MultiField::push(av::Msg& msg) +{ + getValue(); + av_pushMsg(msg, mValue); +} + +template<> void +av::MultiField::pop(av::Msg& msg) +{ + av_popMsg(msg, mValue); + if (mHasSetValueCallback) + mSetValueCallback(SetValueEvent(this, mValue)); + fieldChanged(true); +} + +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) diff --git a/avango-core/src/avango/fields/SingleField.cpp b/avango-core/src/avango/fields/SingleField.cpp new file mode 100644 index 00000000..2df945ce --- /dev/null +++ b/avango-core/src/avango/fields/SingleField.cpp @@ -0,0 +1,302 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +namespace +{ + + template + bool fieldHasType(av::Field* field) + { + AV_ASSERT(field); + return field->getTypeId().isOfType(av::SingleField::getClassTypeId()); + } + + template + ToType convertFieldValue(av::Field* field) + { + av::SingleField* from_field = dynamic_cast*>(field); + AV_ASSERT(from_field); + return static_cast(from_field->getValue()); + } + +} + +template<> +void av::SingleField::pullValueImpl(av::Field* fromField) +{ + AV_ASSERT(fromField); + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::SingleField::pullValueImpl(av::Field* fromField) +{ + AV_ASSERT(fromField); + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + + +template<> +void av::SingleField::pullValueImpl(av::Field* fromField) +{ + AV_ASSERT(fromField); + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::SingleField::pullValueImpl(av::Field* fromField) +{ + AV_ASSERT(fromField); + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::SingleField::pullValueImpl(av::Field* fromField) +{ + AV_ASSERT(fromField); + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::SingleField::pullValueImpl(av::Field* fromField) +{ + AV_ASSERT(fromField); + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} + +template<> +void av::SingleField::pullValueImpl(av::Field* fromField) +{ + AV_ASSERT(fromField); + if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else if (fieldHasType(fromField)) + { + setValue(convertFieldValue(fromField), fromField); + } + else + { + throw std::invalid_argument("pullValue: type mismatch. " + + getTypeId().getName() + + " <--> " + + fromField->getTypeId().getName()); + } +} diff --git a/avango-core/src/avango/fields/StandardFields.cpp b/avango-core/src/avango/fields/StandardFields.cpp new file mode 100644 index 00000000..a1cdc127 --- /dev/null +++ b/avango-core/src/avango/fields/StandardFields.cpp @@ -0,0 +1,82 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + + +AV_FIELD_DEFINE(av::SFBool) +AV_FIELD_DEFINE(av::MFBool) + +AV_FIELD_DEFINE(av::SFDouble) +AV_FIELD_DEFINE(av::MFDouble) + +AV_FIELD_DEFINE(av::SFFloat) +AV_FIELD_DEFINE(av::MFFloat) + +AV_FIELD_DEFINE(av::SFInt) +AV_FIELD_DEFINE(av::MFInt) + +AV_FIELD_DEFINE(av::SFLong) +AV_FIELD_DEFINE(av::MFLong) + +AV_FIELD_DEFINE(av::SFUInt) +AV_FIELD_DEFINE(av::MFUInt) + +AV_FIELD_DEFINE(av::SFULong) +AV_FIELD_DEFINE(av::MFULong) + +AV_FIELD_DEFINE(av::SFString) +AV_FIELD_DEFINE(av::MFString) + + + +void av::initStandardFields() +{ + av::Field::initClass(); + + av::SFBool::initClass("av::SFBool", "av::Field"); + av::MFBool::initClass("av::MFBool", "av::Field"); + + av::SFDouble::initClass("av::SFDouble", "av::Field"); + av::MFDouble::initClass("av::MFDouble", "av::Field"); + + av::SFFloat::initClass("av::SFFloat", "av::Field"); + av::MFFloat::initClass("av::MFFloat", "av::Field"); + + av::SFInt::initClass("av::SFInt", "av::Field"); + av::MFInt::initClass("av::MFInt", "av::Field"); + + av::SFLong::initClass("av::SFLong", "av::Field"); + av::MFLong::initClass("av::MFLong", "av::Field"); + + av::SFUInt::initClass("av::SFUInt", "av::Field"); + av::MFUInt::initClass("av::MFUInt", "av::Field"); + + av::SFULong::initClass("av::SFULong", "av::Field"); + av::MFULong::initClass("av::MFULong", "av::Field"); + + av::SFString::initClass("av::SFString", "av::Field"); + av::MFString::initClass("av::MFString", "av::Field"); +} diff --git a/avango-core/src/avango/fields/tests/TestCloneFields.cpp b/avango-core/src/avango/fields/tests/TestCloneFields.cpp new file mode 100644 index 00000000..bb83f52c --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestCloneFields.cpp @@ -0,0 +1,76 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// includes, project + +#include +#include +#include + +// internal unnamed namespace + +namespace +{ + + TEST(SetValueInUncontainedField) + { + av::SFInt field; + field.setValue(42); + CHECK_EQUAL(42, field.getValue()); + } + + TEST(CloneSingleField) + { + av::SFInt field; + field.setValue(42); + + av::Field* clone = field.clone(); + CHECK_EQUAL(42, dynamic_cast(clone)->getValue()); + } + + TEST(CloneMultiField) + { + av::MFInt field; + std::vector values; + values.push_back(42); values.push_back(21); + field.setValue(values); + + av::Field* clone = field.clone(); + std::vector clone_values = dynamic_cast(clone)->getValue(); + CHECK_EQUAL(2u, clone_values.size()); + CHECK_EQUAL(42, clone_values[0]); + CHECK_EQUAL(21, clone_values[1]); + } + + TEST(CloneGenericField) + { + av::Field* field = new av::SFInt; + dynamic_cast(field)->setValue(42); + + av::Field* clone = field->clone(); + CHECK_EQUAL(42, dynamic_cast(clone)->getValue()); + } + +} // namespace diff --git a/avango-core/src/avango/fields/tests/TestFieldConst.cpp b/avango-core/src/avango/fields/tests/TestFieldConst.cpp new file mode 100644 index 00000000..d1d65b33 --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestFieldConst.cpp @@ -0,0 +1,84 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +#include + +namespace +{ + class MyConstObject : public av::BoolObject + { + AV_FC_DECLARE(); + + public: + + av::MFBool BoolValues; + av::SFBool BoolValue; + + MyConstObject() + { + AV_FC_ADD_FIELD(BoolValues, av::MFBool::ContainerType()); + AV_FC_ADD_FIELD(BoolValue, false); + + } + + void testConstness() const + { + BoolValues.getValue(); + BoolValue.getValue(); + } + }; + + AV_FC_DEFINE(MyConstObject); + + void MyConstObject::initClass() + { + if (!isTypeInitialized()) + { + av::BoolObject::initClass(); + AV_FC_INIT(av::BoolObject, MyConstObject, true); + } + } + + TEST(fieldGetConst) + { + MyConstObject::initClass(); + av::Link obj(new MyConstObject); + av::MFBool::ContainerType testArray(10, true); + + obj->BoolValues.setValue(testArray); + + CHECK_ARRAY_EQUAL(testArray, obj->BoolValues.getValue(), testArray.size()); + } + +} // namespace diff --git a/avango-core/src/avango/fields/tests/TestFieldMultiPush.cpp b/avango-core/src/avango/fields/tests/TestFieldMultiPush.cpp new file mode 100644 index 00000000..d8e1d6e4 --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestFieldMultiPush.cpp @@ -0,0 +1,137 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +// include i/f header + +// includes, system + +// includes, project + +#include +#include +#include +#include + +// variables, exported + +// internal unnamed namespace + +namespace +{ + using namespace av; + + class FieldNodeMultiPush : public av::FieldContainer { + AV_FC_DECLARE(); + + public: + + FieldNodeMultiPush(); + virtual ~FieldNodeMultiPush(); + + SFInt IntField; + SFInt OutField; + + void fieldHasChanged(const av::Field& field); + + private: + unsigned int mTriggered; + + }; + + AV_FC_DEFINE(FieldNodeMultiPush); + + FieldNodeMultiPush::FieldNodeMultiPush() + : mTriggered(0) + { + AV_FC_ADD_FIELD(IntField, 0); + AV_FC_ADD_FIELD(OutField, 0); + } + + FieldNodeMultiPush::~FieldNodeMultiPush() + {} + + void + FieldNodeMultiPush::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + + AV_FC_INIT(av::FieldContainer, FieldNodeMultiPush, false); + } + } + + void + FieldNodeMultiPush::fieldHasChanged(const av::Field& field) + { + if (&field == &IntField) + { +// mTriggered++; +// if (mTriggered < 2) +// { + OutField.setValue(3); +// } + } + + } + + + class InitNodeFixture + { + public: + InitNodeFixture() + { + FieldNodeMultiPush::initClass(); + } + }; + + TEST_FIXTURE(InitNodeFixture, defaultIsMultiPush) + { + Link node1(new FieldNodeMultiPush); + Link node2(new FieldNodeMultiPush); + + node2->IntField.connectFrom(&(node1->IntField)); + + node1->IntField.setValue(2); + CHECK_EQUAL(2, node2->IntField.getValue()); + + node1->IntField.setValue(3); + CHECK_EQUAL(3, node2->IntField.getValue()); + + } + + TEST_FIXTURE(InitNodeFixture, throwIfFieldIsTriggeredTwice) + { + Link node1(new FieldNodeMultiPush); + Link node2(new FieldNodeMultiPush); + + node2->IntField.connectFrom(&(node1->OutField)); + CHECK_THROW(node1->IntField.connectFrom(&(node2->IntField)), std::runtime_error); + + // CHECK_THROW(node1->IntField.setValue(2), std::runtime_error); + + } + +} // namespace + +// functions, exported diff --git a/avango-core/src/avango/fields/tests/TestFieldReferencing.cpp b/avango-core/src/avango/fields/tests/TestFieldReferencing.cpp new file mode 100644 index 00000000..5ddb3a6e --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestFieldReferencing.cpp @@ -0,0 +1,126 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#include +#include +#include +#include + +#include + +namespace +{ + av::Logger& logger(av::getLogger("TestFieldReferencing")); + + class MyObject : public av::FieldContainer + { + AV_FC_DECLARE(); + + public: + + MyObject(bool* deleted = 0); + ~MyObject(); + + private: + + bool *mDeleted; + + }; + + AV_FC_DEFINE(MyObject); + + MyObject::MyObject(bool* deleted) : + FieldContainer(), + mDeleted(deleted) + { + if (mDeleted) *mDeleted = false; + } + + MyObject::~MyObject() + { + if (mDeleted) *mDeleted = true; + } + + void MyObject::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, MyObject, true); + } + } + + TEST(fieldReferencing) + { + MyObject::initClass(); + + bool src_deleted = false; + MyObject *src(new MyObject(&src_deleted)); + src->reference(); + + bool dst_deleted = false; + MyObject *dst(new MyObject(&dst_deleted)); + dst->reference(); + + AVANGO_LOG(logger, av::logging::INFO, "before connect"); + AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("src: %1%") % src->referenceCount())); + AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("dst: %1%") % dst->referenceCount())); + + dst->Name.connectFrom(&src->Name); + AVANGO_LOG(logger, av::logging::INFO, "after connect"); + AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("src: %1%") % src->referenceCount())); + AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("dst: %1%") % dst->referenceCount())); + + // evaluate once because containers have been touched + av::ApplicationInstance::get().evaluate(); + + AVANGO_LOG(logger, av::logging::INFO, "after evaluate"); + AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("src: %1%") % src->referenceCount())); + AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("dst: %1%") % dst->referenceCount())); + + dst->unreference(); + AVANGO_LOG(logger, av::logging::INFO, "after dst unref"); + if (!src_deleted) AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("src: %1%") % src->referenceCount())); + if (!dst_deleted) AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("dst: %1%") % dst->referenceCount())); + + src->unreference(); + AVANGO_LOG(logger, av::logging::INFO, "after src unref"); + if (!src_deleted) AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("src: %1%") % src->referenceCount())); + if (!dst_deleted) AVANGO_LOG(logger, av::logging::INFO, boost::str(boost::format("dst: %1%") % dst->referenceCount())); + + // simulate application exit + av::ApplicationInstance::get().exit(false); + + CHECK(src_deleted); + CHECK(dst_deleted); + } + +} // namespace + +int main() +{ + logger.addConsoleAppender(); + av::ApplicationInstance::get(); + return UnitTest::RunAllTests(); +} + diff --git a/avango-core/src/avango/fields/tests/TestFieldTypeConversion.cpp b/avango-core/src/avango/fields/tests/TestFieldTypeConversion.cpp new file mode 100644 index 00000000..3722270d --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestFieldTypeConversion.cpp @@ -0,0 +1,202 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +// include i/f header + +// includes, system + +// includes, project + +#include +#include +#include +#include + +// variables, exported + +// internal unnamed namespace + +namespace +{ + using namespace av; + + class FieldsNode : public av::FieldContainer { + AV_FC_DECLARE(); + + public: + + FieldsNode(); + virtual ~FieldsNode(); + + SFFloat FloatField; + SFDouble DoubleField; + SFString StringField; + SFBool BoolField; + SFInt IntField; + SFUInt UIntField; + SFLong LongField; + SFULong ULongField; + + private: + + float mFloat; + }; + + AV_FC_DEFINE(FieldsNode); + + FieldsNode::FieldsNode() + : mFloat(0.0f) + { + AV_FC_ADD_FIELD(FloatField, 0.0f); + FloatField.setMultiPush(true); + AV_FC_ADD_FIELD(DoubleField, 0.0); + DoubleField.setMultiPush(true); + AV_FC_ADD_FIELD(StringField, "defaultString"); + StringField.setMultiPush(true); + AV_FC_ADD_FIELD(BoolField, false); + BoolField.setMultiPush(true); + AV_FC_ADD_FIELD(IntField, 0); + IntField.setMultiPush(true); + AV_FC_ADD_FIELD(UIntField, 0); + UIntField.setMultiPush(true); + AV_FC_ADD_FIELD(LongField, 0); + LongField.setMultiPush(true); + AV_FC_ADD_FIELD(ULongField, 0); + ULongField.setMultiPush(true); + } + + FieldsNode::~FieldsNode() + {} + + void + FieldsNode::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + + AV_FC_INIT(av::FieldContainer, FieldsNode, false); + } + } + + class InitNodeFixture + { + public: + InitNodeFixture() + { + + FieldsNode::initClass(); + } + }; + + TEST_FIXTURE(InitNodeFixture, connectSameTypeFields) + { + Link node1(new FieldsNode); + Link node2(new FieldsNode); + + node2->FloatField.connectFrom(&(node1->FloatField)); + + node1->FloatField.setValue(2.0f); + + CHECK_EQUAL(node1->FloatField.getValue(), node2->FloatField.getValue()); + } + + TEST_FIXTURE(InitNodeFixture, connectIncompatibleTypeFieldsThrow) + { + Link node1(new FieldsNode); + Link node2(new FieldsNode); + + CHECK_THROW(node2->DoubleField.connectFrom(&(node1->StringField)), std::invalid_argument); + } + + TEST_FIXTURE(InitNodeFixture, connectDifferentTypeFieldsFloatConvert) + { + Link node1(new FieldsNode); + Link node2(new FieldsNode); + + node2->DoubleField.connectFrom(&(node1->FloatField)); + + node1->FloatField.setValue(2); + + CHECK_EQUAL(node1->FloatField.getValue(), node2->DoubleField.getValue()); + + } + + TEST_FIXTURE(InitNodeFixture, connectDifferentTypeFieldsBool) + { + Link node1(new FieldsNode); + Link node2(new FieldsNode); + + + // check float->bool (true) + node2->BoolField.connectFrom(&(node1->FloatField)); + node1->FloatField.setValue(2.0f); + CHECK_EQUAL(true, node2->BoolField.getValue()); + node2->BoolField.disconnect(); node2->BoolField.setValue(false); + + // check float->bool (false) + node2->BoolField.connectFrom(&(node1->FloatField)); + node1->FloatField.setValue(0.0f); + CHECK_EQUAL(false, node2->BoolField.getValue()); + node2->BoolField.disconnect(); node2->BoolField.setValue(false); + + //check int->bool ( true ) + node2->BoolField.connectFrom(&(node1->IntField)); + node1->IntField.setValue(2); + CHECK_EQUAL(true, node2->BoolField.getValue()); + node2->BoolField.disconnect(); node2->BoolField.setValue(false); + + //check int->bool ( false ) + node2->BoolField.connectFrom(&(node1->IntField)); + node1->IntField.setValue(0); + CHECK_EQUAL(false, node2->BoolField.getValue()); + node2->BoolField.disconnect(); node2->BoolField.setValue(false); + + //check bool->int ( true ) + node2->IntField.connectFrom(&(node1->BoolField)); + node1->BoolField.setValue(true); + CHECK_EQUAL(1, node2->IntField.getValue()); + node2->IntField.disconnect(); + + //check bool->int ( false ) + node2->IntField.connectFrom(&(node1->BoolField)); + node1->BoolField.setValue(false); + CHECK_EQUAL(0, node2->IntField.getValue()); + node2->IntField.disconnect(); + + //check bool->float ( true ) + node2->FloatField.connectFrom(&(node1->BoolField)); + node1->BoolField.setValue(true); + CHECK_EQUAL(1.0f, node2->FloatField.getValue()); + node2->FloatField.disconnect(); + + //check bool->float ( false ) + node2->FloatField.connectFrom(&(node1->BoolField)); + node1->BoolField.setValue(false); + CHECK_EQUAL(0.0f, node2->FloatField.getValue()); + node2->FloatField.disconnect(); + } + +} // namespace + +// functions, exported diff --git a/avango-core/src/avango/fields/tests/TestFieldValueCallbacks.cpp b/avango-core/src/avango/fields/tests/TestFieldValueCallbacks.cpp new file mode 100644 index 00000000..8e3df16a --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestFieldValueCallbacks.cpp @@ -0,0 +1,133 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +#include + +namespace +{ + av::Logger& logger(av::getLogger("TestFieldValueCallbacks")); + + class MyObject : public av::BoolObject + { + AV_FC_DECLARE(); + + public: + + av::MFBool Values; + + MyObject() : + mValue(false) + { + AV_FC_ADD_ADAPTOR_FIELD(Value, + boost::bind(&MyObject::getValueCallback, this, _1), + boost::bind(&MyObject::setValueCallback, this, _1)); + AV_FC_ADD_ADAPTOR_FIELD(Values, + boost::bind(&MyObject::getValuesCallback, this, _1), + boost::bind(&MyObject::setValuesCallback, this, _1)); + } + + bool mValue; + std::vector mValues; + + private: + + void getValueCallback(av::SFBool::GetValueEvent event) + { + *(event.getValuePtr()) = mValue; + } + + void setValueCallback(av::SFBool::SetValueEvent event) + { + mValue = event.getValue(); + } + + void getValuesCallback(av::MFBool::GetValueEvent event) + { + *(event.getValuePtr()) = mValues; + } + + void setValuesCallback(av::MFBool::SetValueEvent event) + { + mValues = event.getValue(); + } + + }; + + AV_FC_DEFINE(MyObject); + + void MyObject::initClass() + { + if (!isTypeInitialized()) + { + av::BoolObject::initClass(); + AV_FC_INIT(av::BoolObject, MyObject, true); + } + } + + TEST(fieldValueValue) + { + MyObject::initClass(); + av::Link obj(new MyObject); + + CHECK_EQUAL(false, obj->mValue); + CHECK_EQUAL(false, obj->Value.getValue()); + + obj->Value.setValue(true); + CHECK_EQUAL(true, obj->mValue); + CHECK_EQUAL(true, obj->Value.getValue()); + + obj->mValue = false; + CHECK_EQUAL(false, obj->mValue); + CHECK_EQUAL(false, obj->Value.getValue()); + + CHECK(obj->mValues.empty()); + CHECK_EQUAL(0, obj->Values.getSize()); + obj->mValues.push_back(true); + CHECK_EQUAL(1, obj->Values.getSize()); + obj->Values.add1Value(true); + CHECK_EQUAL(2, obj->Values.getSize()); + CHECK_EQUAL(2u, obj->mValues.size()); + obj->Values.clear(); + CHECK(obj->Values.isEmpty()); + CHECK(obj->mValues.empty()); + } + +} // namespace + +int main() +{ + logger.addConsoleAppender(); + av::ApplicationInstance::get(); + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/fields/tests/TestFields.cpp b/avango-core/src/avango/fields/tests/TestFields.cpp new file mode 100644 index 00000000..9087f761 --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestFields.cpp @@ -0,0 +1,36 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include + +#include + +int main() +{ + av::getRootLogger().addConsoleAppender(); + av::ApplicationInstance::get(); + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/fields/tests/TestMultiFields.cpp b/avango-core/src/avango/fields/tests/TestMultiFields.cpp new file mode 100644 index 00000000..812b124f --- /dev/null +++ b/avango-core/src/avango/fields/tests/TestMultiFields.cpp @@ -0,0 +1,186 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace +{ + using namespace av; + + class MultiFieldsNode : public av::FieldContainer + { + AV_FC_DECLARE(); + + public: + + MultiFieldsNode(); + virtual ~MultiFieldsNode(); + + MFFloat FloatField; + MFDouble DoubleField; + MFString StringField; + MFBool BoolField; + MFInt IntField; + MFUInt UIntField; + MFLong LongField; + MFULong ULongField; + + private: + + std::vector mFloats; + }; + + AV_FC_DEFINE(MultiFieldsNode); + + MultiFieldsNode::MultiFieldsNode() + { + AV_FC_ADD_FIELD(FloatField, MFFloat::ContainerType()); + FloatField.setMultiPush(true); + AV_FC_ADD_FIELD(DoubleField, MFDouble::ContainerType()); + DoubleField.setMultiPush(true); + AV_FC_ADD_FIELD(StringField, MFString::ContainerType()); + StringField.setMultiPush(true); + AV_FC_ADD_FIELD(BoolField, MFBool::ContainerType()); + BoolField.setMultiPush(true); + AV_FC_ADD_FIELD(IntField, MFInt::ContainerType()); + IntField.setMultiPush(true); + AV_FC_ADD_FIELD(UIntField, MFUInt::ContainerType()); + UIntField.setMultiPush(true); + AV_FC_ADD_FIELD(LongField, MFLong::ContainerType()); + LongField.setMultiPush(true); + AV_FC_ADD_FIELD(ULongField, MFULong::ContainerType()); + ULongField.setMultiPush(true); + } + + MultiFieldsNode::~MultiFieldsNode() + {} + + void + MultiFieldsNode::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + + AV_FC_INIT(av::FieldContainer, MultiFieldsNode, false); + } + } + + class InitNodeFixture + { + public: + InitNodeFixture() + { + + MultiFieldsNode::initClass(); + } + }; + + TEST_FIXTURE(InitNodeFixture, connectSameTypeFields) + { + Link node1(new MultiFieldsNode); + Link node2(new MultiFieldsNode); + + std::vector values; + values.push_back(2.0f); + values.push_back(3.0f); + + node2->FloatField.connectFrom(&(node1->FloatField)); + node1->FloatField.setValue(values); + + CHECK_ARRAY_EQUAL(values, node2->FloatField.getValue(), values.size()); + } + + TEST_FIXTURE(InitNodeFixture, connectIncompatibleTypeFieldsThrow) + { + Link node1(new MultiFieldsNode); + Link node2(new MultiFieldsNode); + + CHECK_THROW(node2->DoubleField.connectFrom(&(node1->StringField)), std::invalid_argument); + } + + TEST_FIXTURE(InitNodeFixture, connectDifferentTypeFieldsFloatConvert) + { + Link node1(new MultiFieldsNode); + Link node2(new MultiFieldsNode); + + node2->DoubleField.connectFrom(&(node1->FloatField)); + + std::vector values; + values.push_back(2.0f); + values.push_back(3.0f); + + node1->FloatField.setValue(values); + + CHECK_ARRAY_EQUAL(values, node2->DoubleField.getValue(), values.size()); + } + + TEST_FIXTURE(InitNodeFixture, connectDifferentTypeFieldsBool) + { + Link node1(new MultiFieldsNode); + Link node2(new MultiFieldsNode); + + std::vector boolVecTrue; + boolVecTrue.push_back(true); + boolVecTrue.push_back(true); + + std::vector boolVecFalse; + boolVecFalse.push_back(false); + boolVecFalse.push_back(false); + + + // check float->bool + std::vector floatVec; + floatVec.push_back(2.0f); + floatVec.push_back(3.0f); + node2->BoolField.connectFrom(&(node1->FloatField)); + node1->FloatField.setValue(floatVec); + CHECK_ARRAY_EQUAL(boolVecTrue, node2->BoolField.getValue(), floatVec.size()); + node2->BoolField.disconnect(); + + //check int->bool ( true ) + std::vector intVec; + intVec.push_back(2); + intVec.push_back(3); + node2->BoolField.connectFrom(&(node1->IntField)); + node1->IntField.setValue(intVec); + CHECK_ARRAY_EQUAL(boolVecTrue, node2->BoolField.getValue(), intVec.size()); + node2->BoolField.disconnect(); + + //check int->bool ( false ) + std::vector intVec2; + intVec2.push_back(0); + intVec2.push_back(0); + node2->BoolField.connectFrom(&(node1->IntField)); + node1->IntField.setValue(intVec2); + CHECK_ARRAY_EQUAL(boolVecFalse, node2->BoolField.getValue(), intVec2.size()); + node2->BoolField.disconnect(); + + } + +} // namespace diff --git a/avango-core/src/avango/interface/Application.cpp b/avango-core/src/avango/interface/Application.cpp new file mode 100644 index 00000000..295f051e --- /dev/null +++ b/avango-core/src/avango/interface/Application.cpp @@ -0,0 +1,207 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::Application")); +} + +av::Application::Application() : + mCleanExit(false), + mKeepRunning(false), + mRealExit(true), + mRunning(false) +{ + av::Init::initClass(); +} + +av::Application::~Application() +{ + // Nothing useful can be done here because we are statically allocated and are destructed + // at some late point at application exit. +} + +void +av::Application::evaluate() +{ + mPreEvaluateContainerCallbackSignal(); + FieldContainer::evaluateAllContainers(); + mPostEvaluateContainerCallbackSignal(); + mRenderCallbackSignal(); +} + +bool +av::Application::running() +{ + return mRunning; +} + +bool +av::Application::start() +{ + if (mRunning) return false; + + mKeepRunning = true; + mRunning = true; + while (mKeepRunning) + { + evaluate(); + } + mRunning = false; + + if (mCleanExit) + { + cleanExit(); + } + + return true; +} + +void +av::Application::startInBackground() +{ + // ?! why boost::thread::thread ?! + // mThread.reset(new boost::thread::thread(boost::bind(&av::Application::start, this))); + mThread.reset(new boost::thread(boost::bind(&av::Application::start, this))); +} + +bool +av::Application::stop() +{ + if (!mRunning) return false; + + mKeepRunning = false; + return true; +} + +void +av::Application::exit(bool realExit) +{ + mRealExit = realExit; + if (mRunning) + { + // let start() call cleanExit() + mCleanExit = true; + stop(); + } + else + { + // call cleanExit() ourselves + cleanExit(); + } +} + +av::Application::CallbackHandle +av::Application::addPreEvaluationContainerCallback(const VoidCallback& callback) +{ + return mPreEvaluateContainerCallbackSignal.connect(callback); +} + +av::Application::CallbackHandle +av::Application::addPostEvaluationContainerCallback(const VoidCallback& callback) +{ + return mPostEvaluateContainerCallbackSignal.connect(callback); +} + +av::Application::CallbackHandle +av::Application::addRenderCallback(const VoidCallback& callback) +{ + return mRenderCallbackSignal.connect(callback); +} + +/* static */ void +av::Application::removeCallback(const CallbackHandle& handle) +{ + handle.disconnect(); +} + +void +av::Application::disconnectAllFields() +{ + ContainerPool::InstancePoolType pool(ContainerPool::getContainerPool()); + + std::vector > containers; + containers.reserve(pool.size()); + ContainerPool::InstancePoolType::const_iterator pool_end(pool.end()); + for (ContainerPool::InstancePoolType::iterator pool_it = pool.begin(); + pool_it != pool_end; ++pool_it) + { + containers.push_back(pool_it->second); + } + + for (std::vector >::iterator container_it = containers.begin(); + container_it != containers.end(); ++container_it) + { + Link container(*container_it); + AVANGO_LOG(logger, logging::DEBUG, boost::str(boost::format("cleanExit: disconnecting fields from container 0x%x (%s)") + % container.getPtr() + % (container->Name.getValue().empty()? "" : container->Name.getValue()))) + container->enableNotify(false); + for_each(container->getFields().begin(), container->getFields().end(), + boost::bind(&Field::disconnect, _1)); + } +} + +void +av::Application::cleanExit() +{ + FieldContainer::unscheduleEvaluationForAllContainers(); + disconnectAllFields(); + + ContainerPool::InstancePoolType pool(ContainerPool::getContainerPool()); + if (!pool.empty()) + { + AVANGO_LOG(logger, logging::WARN, "cleanExit: container pool still not empty after cleanup:") + ContainerPool::InstancePoolType::const_iterator pool_end(pool.end()); + for (ContainerPool::InstancePoolType::iterator pool_it = pool.begin(); + pool_it != pool_end; ++pool_it) + { + Link container(pool_it->second); + AVANGO_LOG(logger, logging::DEBUG, boost::str(boost::format(" 0x%x (%s)") + % container.getPtr() + % (container->Name.getValue().empty()? "" : container->Name.getValue()))) + } + } + + if (mRealExit) + { + std::exit(0); + } +} diff --git a/avango-core/src/avango/interface/FieldContainerHelper.cpp b/avango-core/src/avango/interface/FieldContainerHelper.cpp new file mode 100644 index 00000000..6d4791aa --- /dev/null +++ b/avango-core/src/avango/interface/FieldContainerHelper.cpp @@ -0,0 +1,42 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + + +void +av::disconnectAndClearAllFields(FieldContainer* fieldContainer) +{ + if (fieldContainer != 0) + { + std::vector &fields = fieldContainer->getFields(); + for (std::vector::iterator field = fields.begin(); field != fields.end(); ++field) + { + (*field)->disconnectAuditors(); + (*field)->disconnect(); + (*field)->clear(); + } + } +} diff --git a/avango-core/src/avango/interface/TimeSensor.cpp b/avango-core/src/avango/interface/TimeSensor.cpp new file mode 100644 index 00000000..2e617002 --- /dev/null +++ b/avango-core/src/avango/interface/TimeSensor.cpp @@ -0,0 +1,94 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + + + +#if defined(_WIN32) +#include +#include +#else +#include +#endif + +#include +#include + +#include + +namespace +{ + av::Logger& logger(av::Logger::getLogger("av::TimeSensor")); + + void getRealTime(const av::SFDouble::GetValueEvent& event) + { +#if defined(_WIN32) + struct _timeb t; + _ftime_s(&t); + (*event.getValuePtr()) = t.time + (t.millitm/1000.0); +#else + timeval t; + gettimeofday(&t, 0); + (*event.getValuePtr()) = t.tv_sec + (t.tv_usec/1000000.0); +#endif + } + + void setRealTime(const av::SFDouble::SetValueEvent&) + { + AVANGO_LOG(logger, av::logging::WARN, "RealTime is read-only") + } +} + +AV_FC_DEFINE(av::TimeSensor); + +av::TimeSensor::TimeSensor() +{ + AV_FC_ADD_ADAPTOR_FIELD(RealTime, &getRealTime, &setRealTime); + AV_FC_ADD_FIELD(ReferenceTime, RealTime.getValue()); + AV_FC_ADD_FIELD(Time, 0); + + alwaysEvaluate(true); +} + +av::TimeSensor::~TimeSensor() +{} + +void +av::TimeSensor::initClass() +{ + if (!isTypeInitialized()) + { + FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, av::TimeSensor, true); + } +} + +/* virtual */ void +av::TimeSensor::evaluate() +{ + Time.setValue(RealTime.getValue()-ReferenceTime.getValue()); + RealTime.touch(); +} diff --git a/avango-core/src/avango/interface/tests/TestApplication.cpp b/avango-core/src/avango/interface/tests/TestApplication.cpp new file mode 100644 index 00000000..58eac66f --- /dev/null +++ b/avango-core/src/avango/interface/tests/TestApplication.cpp @@ -0,0 +1,123 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include +#include + +#include + +namespace +{ + bool my_object_destroyed = true; + + class MyObject : public av::IntObject + { + AV_FC_DECLARE(); + + public: + + MyObject(); + ~MyObject(); + + virtual void evaluate(); + + private: + + int mEvaluateCount; + }; + + AV_FC_DEFINE(MyObject); + + MyObject::MyObject() : + mEvaluateCount(10) + { + my_object_destroyed = false; + } + + MyObject::~MyObject() + { + my_object_destroyed = true; + } + + void MyObject::evaluate() + { + Value.setValue(42); + + if (--mEvaluateCount <= 0) + { + av::ApplicationInstance::get().exit(false); + } + } + + void MyObject::initClass() + { + if (!isTypeInitialized()) + { + av::IntObject::initClass(); + AV_FC_INIT(av::IntObject, MyObject, true); + } + } + + TEST(ApplicationEvaluate) + { + av::Link my_obj(new MyObject()); + my_obj->touch(); + av::ApplicationInstance::get().evaluate(); + CHECK_EQUAL(42, my_obj->Value.getValue()); + my_obj.clear(); + CHECK(my_object_destroyed); + } + + TEST(ApplicationExit) + { + av::Link my_obj(new MyObject()); + my_obj->touch(); + my_obj.clear(); + av::ApplicationInstance::get().exit(false); + CHECK(my_object_destroyed); + } + + TEST(ApplicationExitFromMainLoop) + { + av::Link my_obj(AV_NEW(MyObject)); + my_obj->alwaysEvaluate(true); + av::ApplicationInstance::get().start(); + my_obj.clear(); + CHECK(my_object_destroyed); + } +} + +int main() +{ + av::getLogger("av::Application").addConsoleAppender(); + av::getLogger("av::Application").setLevel(av::logging::DEBUG); + + av::ApplicationInstance::get(); + MyObject::initClass(); + + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/interface/tests/TestTimeSensor.cpp b/avango-core/src/avango/interface/tests/TestTimeSensor.cpp new file mode 100644 index 00000000..c99f1615 --- /dev/null +++ b/avango-core/src/avango/interface/tests/TestTimeSensor.cpp @@ -0,0 +1,68 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include + +namespace +{ + TEST(TimeSensor) + { + av::TimeSensor::initClass(); + av::Link time_sensor(new av::TimeSensor); + av::ApplicationInstance::get().evaluate(); + double real_time = time_sensor->RealTime.getValue(); + CHECK(real_time > 0); + double old_time = real_time; +#ifdef _WIN32 + Sleep(50); +#else + usleep(50000); +#endif + av::ApplicationInstance::get().evaluate(); + real_time = time_sensor->RealTime.getValue(); + av::getRootLogger().info() << "real_time - old_time : " << real_time - old_time; + CHECK(old_time < real_time); + } +} + +int main() +{ + av::getRootLogger().addConsoleAppender(); + av::ApplicationInstance::get(); + + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/logging/ConsoleAppender.cpp b/avango-core/src/avango/logging/ConsoleAppender.cpp new file mode 100644 index 00000000..fa424d56 --- /dev/null +++ b/avango-core/src/avango/logging/ConsoleAppender.cpp @@ -0,0 +1,37 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/logging/ConsoleAppender.h" + +#include + +#include + + +/* virtual */ void +av::logging::ConsoleAppender::doAppend(LoggingEvent& event) +{ + std::clog << event.getFormattedString() << std::endl; +} diff --git a/avango-core/src/avango/logging/FileAppender.cpp b/avango-core/src/avango/logging/FileAppender.cpp new file mode 100644 index 00000000..b2dc2042 --- /dev/null +++ b/avango-core/src/avango/logging/FileAppender.cpp @@ -0,0 +1,56 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/logging/FileAppender.h" + +#include + + +av::logging::FileAppender::FileAppender(const std::string& filename) + : mLogFile(filename.c_str(), std::ios_base::app) +{ + if (!mLogFile.is_open()) + throw std::ios::failure("Could not open file " + filename); +} + + +av::logging::FileAppender::~FileAppender() +{} + + +const std::string& +av::logging::FileAppender::getFilename() const +{ + return mFilename; +} + +/* virtual */ void +av::logging::FileAppender::doAppend(LoggingEvent& event) +{ + mLogFile << event.getFormattedString() << std::endl; + + // probably inefficient, currently needed for correct serialization of log messages, see tests + mLogFile.flush(); +} diff --git a/avango-core/src/avango/logging/Level.cpp b/avango-core/src/avango/logging/Level.cpp new file mode 100644 index 00000000..5194564d --- /dev/null +++ b/avango-core/src/avango/logging/Level.cpp @@ -0,0 +1,44 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/logging/Level.h" + +#include + +const std::string& +av::logging::levelToString(Level level) +{ + static std::string sLevelString[] = + { + "FATAL", + "ERROR", + "WARN ", + "INFO ", + "DEBUG", + "TRACE", + }; + + return sLevelString[level]; +} diff --git a/avango-core/src/avango/logging/Logger.cpp b/avango-core/src/avango/logging/Logger.cpp new file mode 100644 index 00000000..eca29fb8 --- /dev/null +++ b/avango-core/src/avango/logging/Logger.cpp @@ -0,0 +1,288 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +av::logging::Logger& +av::logging::Logger::getRootLogger() +{ + return LoggerManagerInstance::get().getRootLogger(); +} + +av::logging::Logger& +av::logging::Logger::getLogger(const std::string& name) +{ + return LoggerManagerInstance::get().getLogger(name); +} + +av::logging::Logger::Logger(const std::string& name, Level level) : + mName(name), + mLevel(level), + mParent(0) +{} + +void +av::logging::Logger::setParent(Logger* parent) +{ + AV_ASSERT(parent); + mParent = parent; +} + +av::logging::Logger::Stream +av::logging::Logger::operator()(Level level) +{ + return Stream(*this, level); +} + +void +av::logging::Logger::log(Level level, const std::string& msg) +{ + LoggingEvent event(*this, level, msg); + passMessage(event); +} + +void +av::logging::Logger::fatal(const std::string& msg) +{ + log(FATAL, msg); +} + +av::logging::Logger::Stream av::logging::Logger::fatal() +{ + return Stream(*this, FATAL); +} + +void +av::logging::Logger::error(const std::string& msg) +{ + log(ERROR, msg); +} + +av::logging::Logger::Stream av::logging::Logger::error() +{ + return Stream(*this, ERROR); +} + +void +av::logging::Logger::warn(const std::string& msg) +{ + log(WARN, msg); +} + +av::logging::Logger::Stream av::logging::Logger::warn() +{ + return Stream(*this, WARN); +} + +void +av::logging::Logger::info(const std::string& msg) +{ + log(INFO, msg); +} + +av::logging::Logger::Stream av::logging::Logger::info() +{ + return Stream(*this, INFO); +} + +void +av::logging::Logger::debug(const std::string& msg) +{ + log(DEBUG, msg); +} + +av::Logger::Stream av::logging::Logger::debug() +{ + return Stream(*this, DEBUG); +} + +void +av::logging::Logger::trace(const std::string& msg) +{ + log(TRACE, msg); +} + +av::logging::Logger::Stream av::logging::Logger::trace() +{ + return Stream(*this, TRACE); +} + +void +av::logging::Logger::passMessage(LoggingEvent& event) +{ + size_t listSize = mAppenders.size(); + if (event.getLevel() <= mLevel) + { + boost::mutex::scoped_lock lock(mAppenderMutex); + if (listSize == mAppenders.size()) + { + std::for_each(mAppenders.begin(), mAppenders.end(), + boost::bind(&Appender::doAppend, _1, event)); + } + } + if (mParent) + { + mParent->passMessage(event); + } +} + +const std::string& +av::logging::Logger::getName() const +{ + return mName; +} + +bool +av::logging::Logger::hasParent() const +{ + return mParent; +} + +const av::logging::Logger& +av::logging::Logger::getParent() const +{ + if (mParent) + { + return *mParent; + } + else + { + AV_ASSERT(this == &getRootLogger()); + throw std::logic_error("av::logging::Logger::getParent: Logger has no parent."); + return *this; + } +} + +av::logging::Logger& +av::logging::Logger::getParent() +{ + if (mParent) + { + return *mParent; + } + else + { + AV_ASSERT(this == &getRootLogger()); + throw std::logic_error("av::logging::Logger::getParent: Logger has no parent."); + return *this; + } +} + +av::logging::Level +av::logging::Logger::getLevel() const +{ + return mLevel; +} + +void +av::logging::Logger::setLevel(Level level) +{ + mLevel = level; +} + +void +av::logging::Logger::addAppender(boost::shared_ptr appender) +{ + boost::mutex::scoped_lock lock(mAppenderMutex); + mAppenders.insert(appender); +} + +void +av::logging::Logger::addConsoleAppender() +{ + addAppender(ConsoleAppenderInstance::getAsSharedPtr()); +} + +void +av::logging::Logger::removeAppender(boost::shared_ptr appender) +{ + boost::mutex::scoped_lock lock(mAppenderMutex); + mAppenders.erase(appender); +} + +void +av::logging::Logger::removeConsoleAppender() +{ + removeAppender(ConsoleAppenderInstance::getAsSharedPtr()); +} + +void +av::logging::Logger::removeAllAppenders() +{ + boost::mutex::scoped_lock lock(mAppenderMutex); + mAppenders.clear(); +} + +bool +av::logging::Logger::isActive(Level level) const +{ + return ( (!mAppenders.empty() && level <= mLevel) || ( hasParent() && getParent().isActive(level))); +} + +const std::set, av::logging::Logger::compareSharedPtrs >& +av::logging::Logger::getAppenders() const +{ + return mAppenders; +} + +av::logging::Logger::Stream::Stream(Logger& logger, Level level) : + mLogger(logger), + mLevel(level), + mBuf() +{} + +av::logging::Logger::Stream::~Stream() +{ + flush(); +} + +void +av::logging::Logger::Stream::flush() +{ + if (0 == mFormatter.size()) + { + if (0 != mBuf.str().size()) + { + mLogger.log(mLevel, mBuf.str()); + } + } + else + { + mLogger.log(mLevel, mFormatter.str()); + } + mBuf.clear(); + mBuf.str(""); + mFormatter.clear(); +} diff --git a/avango-core/src/avango/logging/LoggerManager.cpp b/avango-core/src/avango/logging/LoggerManager.cpp new file mode 100644 index 00000000..9234794d --- /dev/null +++ b/avango-core/src/avango/logging/LoggerManager.cpp @@ -0,0 +1,120 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include + +namespace +{ + + std::string getParentLoggerName(const std::string& name) + { + if (name.find(":::") != std::string::npos) + { + throw std::invalid_argument("av::logging::LoggerManager::getParentLoggerName: " + "name must not contain ':::'"); + } + if (name.rfind("::") == name.size()-2) + { + throw std::invalid_argument("av::logging::LoggerManager::getParentLoggerName: " + "name must not end with '::'"); + } + + size_t parent_idx = name.rfind("::"); + if (parent_idx != std::string::npos) + { + return name.substr(0, parent_idx); + } + else + { + return ""; + } + } + +} // namespace + +av::logging::LoggerManager::LoggerManager() +{ + // create root logger + mRootLogger = new Logger(); + mLoggerMap[""] = mRootLogger; +} + +av::logging::LoggerManager::~LoggerManager() +{ + LoggerMap::const_iterator it = mLoggerMap.begin(); + LoggerMap::const_iterator it_end = mLoggerMap.end(); + + for (; it != it_end; ++it ) + { + delete (it->second); + } + mRootLogger = 0; +} + +av::logging::LoggerManager::LoggerMap& +av::logging::LoggerManager::getLoggerMap() +{ + return mLoggerMap; +} + +av::logging::Logger& +av::logging::LoggerManager::getRootLogger() +{ + return *mRootLogger; +} + +av::logging::Logger& +av::logging::LoggerManager::getLogger(const std::string& name) +{ + if (0 == mRootLogger->getName().compare(name)) + { + return *mRootLogger; + } + + // creates parent logger if necessary + Logger *parent_logger(&getLogger(getParentLoggerName(name))); + + { + // lock after creating parent logger to avoid recursive locking + boost::mutex::scoped_lock lock(mLoggerMapMutex); + + typedef LoggerMap::const_iterator iter; + iter it = mLoggerMap.find(name); + iter it_end = mLoggerMap.end(); + + if (it == it_end) // not in map + { + Logger* logger = new Logger(name); + logger->setParent(parent_logger); + mLoggerMap[name] = logger; + return *logger; + } + else + { + return *(it->second); + } + } +} diff --git a/avango-core/src/avango/logging/LoggingEvent.cpp b/avango-core/src/avango/logging/LoggingEvent.cpp new file mode 100644 index 00000000..95acb3ef --- /dev/null +++ b/avango-core/src/avango/logging/LoggingEvent.cpp @@ -0,0 +1,97 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/logging/LoggingEvent.h" + +#include + +#if defined(_WIN32) +#include +#include +#else +#include +#endif + +av::logging::LoggingEvent::LoggingEvent(Logger& logger, + Level level, + const std::string& msg) : + mLogger(logger), + mMsg(msg), + mLevel(level) +{ +#if defined(_WIN32) + struct _timeb now; + _ftime_s(&now); + mTimeStamp = now.time + (now.millitm/1000.0); +#else + timeval now; + gettimeofday(&now,NULL); + mTimeStamp = now.tv_sec + (now.tv_usec/1000000.); +#endif +} + +av::logging::LoggingEvent::~LoggingEvent() +{} + +av::logging::Logger& +av::logging::LoggingEvent::getLogger() +{ + return mLogger; +} + +const std::string& +av::logging::LoggingEvent::getMessage() const +{ + return mMsg; +} + +double +av::logging::LoggingEvent::getTimeStamp() const +{ + return mTimeStamp; +} + +av::logging::Level +av::logging::LoggingEvent::getLevel() +{ + return mLevel; +} + +std::string +av::logging::LoggingEvent::getFormattedString() +{ + std::ostringstream os; + + os << "[" << levelToString(mLevel); + + if (!getLogger().getName().empty()) + { + os << " " << getLogger().getName(); + } + + os << "] " << getMessage(); + + return os.str(); +} diff --git a/avango-core/src/avango/logging/StreamAppender.cpp b/avango-core/src/avango/logging/StreamAppender.cpp new file mode 100644 index 00000000..2a5583fb --- /dev/null +++ b/avango-core/src/avango/logging/StreamAppender.cpp @@ -0,0 +1,42 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +av::logging::StreamAppender::StreamAppender(std::ostream& os) : + mStream(os) +{} + +/* virtual */ +av::logging::StreamAppender::~StreamAppender() +{} + +/* virtual */ void +av::logging::StreamAppender::doAppend(LoggingEvent& event) +{ + mStream << event.getFormattedString() << std::endl; +} diff --git a/avango-core/src/avango/logging/tests/TestLogging.cpp b/avango-core/src/avango/logging/tests/TestLogging.cpp new file mode 100644 index 00000000..240b6eef --- /dev/null +++ b/avango-core/src/avango/logging/tests/TestLogging.cpp @@ -0,0 +1,241 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +// includes, system + +#include +#include +#include + +// includes, project + +#include +#include +#include +#include + +#include + +// variables, exported + +// internal unnamed namespace + +namespace +{ + const char* build_filename(void) + { + static const char* fallback = "log-file.txt"; + const char* envname = std::getenv("AVANGO_TEST_LOG"); + if (envname != 0) + return envname; + else + return fallback; + } + std::string filename(build_filename()); + + void clearFile() + { + std::ofstream output(filename.c_str(), std::ios_base::trunc); + output.close(); + } + + TEST(useLogger) + { + clearFile(); + av::Logger& z = av::Logger::getLogger("useLogger::Group"); + av::Logger& y = av::Logger::getLogger("useLogger::Node"); + av::Logger& x = av::Logger::getLogger("useLogger"); + + x.info("log message using log() method"); + y.info("log message using log() method"); + z.info("useLogger: log message using log() method"); + + boost::shared_ptr file_app(new av::logging::FileAppender(filename)); + x.addAppender(file_app); + + x.info("log message using log() method"); + x.info() << "streamed log message"; + x.info() << "before -- %s %x %.1f -- after" , "1", 42, 5.45; + + x.removeAllAppenders(); + + std::ifstream input(filename.c_str()); + + CHECK(input.is_open()); + + std::string line; + int count = 0; + + while(!input.eof()) + { + getline(input, line); + count++; + + if(count == 1) + { + CHECK( (std::string::npos != line.find("log message using log() method", 0)) ); + } + else if (count == 2) + { + CHECK( (std::string::npos != line.find("streamed log message", 0)) ); + } + else if (count == 3) + { + CHECK( (std::string::npos != line.find("before -- 1 2a 5.5 -- after", 0)) ); + } + } + + input.close(); + } + + TEST(useLoggerHierarchy) + { + clearFile(); + + av::Logger& z = av::Logger::getLogger("useLoggerHierarchy::Group"); + av::Logger& y = av::Logger::getLogger("useLoggerHierarchy::Node"); + av::Logger& x = av::Logger::getLogger("useLoggerHierarchy"); + + boost::shared_ptr file_app(new av::logging::FileAppender(filename)); + + x.addAppender(file_app); + y.addAppender(file_app); + z.addAppender(file_app); + + x.setLevel(av::logging::ERROR); + y.setLevel(av::logging::FATAL); + z.setLevel(av::logging::ERROR); + + x.error() << "error message that should appear once"; + y.info() << "info message that should NOT appear"; + z.error() << "error message that should appear two times"; + + std::ifstream input(filename.c_str()); + + CHECK(input.is_open()); + + std::string line; + int count = 0; + while (!input.eof()) + { + getline(input, line); + count++; + + if (count == 1) + { + CHECK( (std::string::npos != line.find( + "error message that should appear once", 0))); + } + else if (count == 2|| count == 3) + { + CHECK( (std::string::npos != line.find( + "error message that should appear two times", 0))); + } + } + + input.close(); + + x.removeAllAppenders(); + y.removeAllAppenders(); + z.removeAllAppenders(); + } + + TEST(useLoggerStream) + { + av::Logger& logger = av::Logger::getLogger("useLoggerStream"); + + std::ostringstream os; + boost::shared_ptr stream_app(new av::logging::StreamAppender(os)); + + logger.addAppender(stream_app); + + av::Logger::Logger::Stream info(logger, av::logging::INFO); + info << "test message"; + info.flush(); + + logger.removeAppender(stream_app); + + CHECK(os.str().find("test message") != std::string::npos); + } + + TEST(addConsoleAppender) + { + av::Logger& logger = av::Logger::getLogger("consoleLogger"); + av::Logger::getRootLogger().addConsoleAppender(); + av::Logger::getRootLogger().addConsoleAppender(); + logger.info() << "consoleLogger: added console appender two times"; + CHECK(av::Logger::getRootLogger().getAppenders().size() == 1); + } + + TEST(isActive) + { + av::Logger& child = av::Logger::getLogger("useLoggerHierarchy::Node"); + av::Logger& parent = av::Logger::getLogger("useLoggerHierarchy"); + + boost::shared_ptr file_app(new av::logging::FileAppender(filename)); + parent.addAppender(file_app); + + parent.setLevel(av::logging::ERROR); + child.setLevel(av::logging::FATAL); + + CHECK(child.isActive(av::logging::ERROR)); + } + + TEST(LOGMacroSuccessfulLogging) + { + av::Logger& logger = av::Logger::getLogger("useLoggerHierarchy"); + std::ostringstream os; + boost::shared_ptr stream_app(new av::logging::StreamAppender(os)); + logger.addAppender(stream_app); + logger.setLevel(av::logging::ERROR); + + AVANGO_LOG(logger, av::logging::ERROR, "Test"); + + CHECK(!os.str().empty()); + } + + TEST(LOGMacroUnsuccessfulLogging) + { + av::Logger& logger = av::Logger::getLogger("useLoggerHierarchy"); + std::ostringstream os; + boost::shared_ptr stream_app(new av::logging::StreamAppender(os)); + logger.addAppender(stream_app); + logger.setLevel(av::logging::ERROR); + + AVANGO_LOG(logger, av::logging::WARN, "Test"); + + CHECK(os.str().empty()); + } + +} // namespace + +// functions, exported + +int main() +{ + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/network/CMakeLists.txt b/avango-core/src/avango/network/CMakeLists.txt new file mode 100644 index 00000000..0fc16102 --- /dev/null +++ b/avango-core/src/avango/network/CMakeLists.txt @@ -0,0 +1,17 @@ +IF (AVANGO_DISTRIBUTION_SUPPORT) + FILE(GLOB AVANGO_CORE_DISTRIBUTION_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + + ) + LIST (APPEND AVANGO_CORE_SRC ${AVANGO_CORE_DISTRIBUTION_SRC}) +ENDIF (AVANGO_DISTRIBUTION_SUPPORT) + +IF (AVANGO_ZMQ_DISTRIBUTION_SUPPORT) + FILE(GLOB AVANGO_CORE_DISTRIBUTION_ZMQ_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + src/avango/network/*.cpp + include/avango/*.h + include/avango/logging/*.h + ) + LIST (APPEND AVANGO_CORE_SRC ${AVANGO_CORE_DISTRIBUTION_ZMQ_SRC}) +ENDIF (AVANGO_ZMQ_DISTRIBUTION_SUPPORT) + + diff --git a/avango-core/src/avango/network/Helper.cpp b/avango-core/src/avango/network/Helper.cpp new file mode 100644 index 00000000..247bba3e --- /dev/null +++ b/avango-core/src/avango/network/Helper.cpp @@ -0,0 +1,51 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "Helper.h" + +#include + +#include +#include +#include + +std::string +av::getName(const Link& obj) +{ + if (!obj.isValid()) + { + throw std::invalid_argument("av::getName(): obj not valid"); + } + + FieldContainer* fc = dynamic_cast(obj.getPtr()); + if (!fc || fc->Name.getValue().empty()) + { + return "unnamed"; + } + else + { + return fc->Name.getValue(); + } +} diff --git a/avango-core/src/avango/network/Helper.h b/avango-core/src/avango/network/Helper.h new file mode 100644 index 00000000..9ef26518 --- /dev/null +++ b/avango-core/src/avango/network/Helper.h @@ -0,0 +1,39 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_HELPER_H) +#define AVANGO_HELPER_H + +#include + +#include +#include + +namespace av +{ + std::string getName(const Link&); +} + +#endif // #if !defined(AVANGO_HELPER_H) diff --git a/avango-core/src/avango/network/MaestroEID.cpp b/avango-core/src/avango/network/MaestroEID.cpp new file mode 100644 index 00000000..403b2bf5 --- /dev/null +++ b/avango-core/src/avango/network/MaestroEID.cpp @@ -0,0 +1,244 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +av::MaestroEID::MaestroEID(Maestro_ErrorHandler* error_handler) : + Maestro_EndpID(error_handler) +{} + +av::MaestroEID::MaestroEID(hot_endpt_t ep, Maestro_ErrorHandler* error_handler) : + Maestro_EndpID(ep, error_handler) +{} + +av::MaestroEID::MaestroEID(const MaestroEID& eid) : + Maestro_Base(), Maestro_EndpID(eid.endpID) +{} + +av::MaestroEID::MaestroEID(const Maestro_EndpID& eid) : + Maestro_EndpID(eid.getHotEndpt()) +{} + +bool +av::MaestroEID::operator< (const MaestroEID &eid) const +{ + return (::strncmp(c_str(), eid.c_str(), HOT_ENDP_MAX_NAME_SIZE) < 0); +} + +bool +av::MaestroEID::operator== (const MaestroEID &eid) const +{ + return (::strncmp(c_str(), eid.c_str(), HOT_ENDP_MAX_NAME_SIZE) == 0); +} + +bool +av::MaestroEID::operator!= (const MaestroEID &eid) const +{ + return !MaestroEID::operator== (eid); +} + +const av::MaestroEID& +av::MaestroEID::operator=(const MaestroEID& eid) +{ + Maestro_EndpID::operator=(const_cast (eid)); + return *this; +} + +const av::MaestroEID& +av::MaestroEID::operator=(const Maestro_EndpID& eid) +{ + Maestro_EndpID::operator=(const_cast (eid)); + return *this; +} + +const char* +av::MaestroEID::c_str() const +{ + return endpID.name; +} + +Maestro_Message& +av::operator<< (Maestro_Message &msg, const MaestroEID& eid) +{ + const_cast (eid).operator>>(msg); + return msg; +} + +Maestro_Message& +av::operator>> (Maestro_Message &msg, MaestroEID& eid) +{ + eid.operator<<(msg); + return msg; +} + +std::ostream& +av::operator<<(std::ostream& os, const MaestroEID& eid) +{ + return os << eid.c_str(); +} + +size_t +av::MaestroEID::Hasher::operator() (const MaestroEID& eid) const +{ + return mHasher(eid.c_str()); +} + +av::MaestroEID_list::MaestroEID_list() +{} + +av::MaestroEID_list::~MaestroEID_list() +{} + +av::MaestroEID_list::MaestroEID_list(const MaestroEID_list& l) : + MaestroEID_set(l) +{} + +av::MaestroEID_list::MaestroEID_list(const Maestro_EndpList& l) +{ + for (unsigned int i = 0; i < l.size(); i++) insert(l[i]); +} + +const av::MaestroEID_list& +av::MaestroEID_list::operator=(const Maestro_EndpList& l) +{ + clear(); + for (unsigned int i = 0; i < l.size(); i++) insert(l[i]); + return *this; +} + +Maestro_Message& +av::operator<<(Maestro_Message &msg, const MaestroEID_list& l) +{ + MaestroEID_list::const_iterator i; + + for (i = l.begin(); i != l.end(); i++) + { + MaestroEID eid = (*i); + msg << eid; + } + + return msg << static_cast (l.size()); +} + +Maestro_Message& +av::operator>> (Maestro_Message &msg, MaestroEID_list& l) +{ + l.clear(); + + int size; + + msg >> size; + + for (int i = 0; i < size; i++) + { + MaestroEID eid; + msg >> eid; + l.insert(eid); + } + + return msg; +} + +std::ostream& +av::operator<<(std::ostream& os, const MaestroEID_list& l) +{ + MaestroEID_list::const_iterator i; + + for (i = l.begin(); i != l.end(); i++) + { + os << (*i); + + if (l.end() != i) + os << " "; + } + + return os; +} + +av::MaestroEID_eidlist_map::MaestroEID_eidlist_map() +{} + +av::MaestroEID_eidlist_map::~MaestroEID_eidlist_map() +{} + +av::MaestroEID_eidlist_map::MaestroEID_eidlist_map(const MaestroEID_eidlist_map& m) : + MaestroEID_eidlist_map_base(m) +{} + +Maestro_Message& +av::operator<< (Maestro_Message &msg, const MaestroEID_eidlist_map& m) +{ + MaestroEID_eidlist_map::const_iterator i; + + for (i = m.begin(); i != m.end(); ++i) + { + msg << (*i).second; + msg << (*i).first; + } + + return msg << static_cast (m.size()); +} + +Maestro_Message& +av::operator>> (Maestro_Message &msg, MaestroEID_eidlist_map& m) +{ + m.clear(); + + int size; + + msg >> size; + + for (int i = 0; i < size; i++) + { + MaestroEID eid; + MaestroEID_list eid_list; + + msg >> eid; + msg >> eid_list; + + m[eid] = eid_list; + } + + return msg; +} + +std::ostream& +av::operator<<(std::ostream& os, const MaestroEID_eidlist_map& m) +{ + MaestroEID_eidlist_map::const_iterator i; + + for (i = m.begin(); i != m.end(); i++) + { + os << " " + << (*i).first + << " : " + << (*i).second + << std::endl; + } + + return os; +} diff --git a/avango-core/src/avango/network/MaestroMerge.cpp b/avango-core/src/avango/network/MaestroMerge.cpp new file mode 100644 index 00000000..68863d12 --- /dev/null +++ b/avango-core/src/avango/network/MaestroMerge.cpp @@ -0,0 +1,524 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "MaestroMerge.h" + +#include +#include + +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::MaestroMerge")); +} + +av::MaestroMerge::MaestroMerge(MaestroMergeOptions &ops) : + Maestro_Base(), + Maestro_GroupMember(ops), + mFirstViewInstalled(0), + mBlocked(false), + mValidStateGuro(0), + mXferInProgress(0) +{ + mMyView.stateCounter = 0; +} + +av::MaestroMerge::MaestroMerge(MaestroMerge& hMerge) : + Maestro_Base(hMerge), + Maestro_GroupMember(hMerge) +{ + AVANGO_LOG(logger, logging::ERROR, "copy constructor not supported") +} + +av::MaestroMerge& av::MaestroMerge::operator= (MaestroMerge&) +{ + AVANGO_LOG(logger, logging::ERROR, "operator= not supported") + return *this; +} + +void +av::MaestroMerge::join() +{ + Maestro_GroupMember::join(); + AVANGO_LOG(logger, logging::DEBUG, "join") +} + +void +av::MaestroMerge::leave() +{ + Maestro_GroupMember::leave(); + mFirstViewInstalled = 0; + AVANGO_LOG(logger, logging::DEBUG, "leave") +} + +/**************************** cast **************************************/ + +void +av::MaestroMerge::cast(Maestro_Message &msg) +{ + msg << (int) MAESTRO_MERGE_CAST; + Maestro_MsgSendView sendView = MAESTRO_MSG_SEND_CURRENT_VIEW; + + if (mXferInProgress) + { + delayMessage(msg); + } + else + { + Maestro_GroupMember::cast(msg, sendView); + } +} + +void +av::MaestroMerge::cast(Maestro_Message &msg, Maestro_MsgSendView &sendView) +{ + msg << (int) MAESTRO_MERGE_CAST; + + if (mXferInProgress) + { + delayMessage(msg, sendView); + } + else + { + Maestro_GroupMember::cast(msg, sendView); + } +} + +/**************************** send **************************************/ + +void +av::MaestroMerge::send(Maestro_EndpID &dest, Maestro_Message &msg) +{ + msg << (int) MAESTRO_MERGE_SEND; + Maestro_MsgSendView sendView = MAESTRO_MSG_SEND_CURRENT_VIEW; + + if (mXferInProgress) + { + delayMessage(dest, msg); + } + else + { + Maestro_GroupMember::send(dest, msg, sendView); + } +} + +void +av::MaestroMerge::send(Maestro_EndpID &dest, Maestro_Message &msg, Maestro_MsgSendView &sendView) +{ + msg << (int) MAESTRO_MERGE_SEND; + + if (mXferInProgress) + { + delayMessage(dest, msg, sendView); + } + else + { + Maestro_GroupMember::send(dest, msg, sendView); + } +} + +/************************************************************************/ +/****************** Overloaded Maestro_GroupMember upcalls **************/ +/************************************************************************/ + +/******************* grpMemb_AcceptedView_Callback **********************/ + +void +av::MaestroMerge::grpMemb_AcceptedView_Callback(Maestro_GrpMemb_ViewData &gmView, + Maestro_Message &msg) +{ + // Extract membership info from the view message. + MaestroMergeViewData vd(gmView); + vd.blend_in(msg); + + if (logger.isActive(logging::DEBUG)) + { + logger.debug() << "grpMemb_AcceptedView_Callback: " + //<< vd.viewID + << " [" + << (vd.coordinator == vd.myEndpID ? " coordinator" : "") + << "]"; + + for (size_t i = 0; i < vd.members.size(); i++) + { + MaestroEID eid(vd.members[i]); + + logger.debug() << "grpMemb_AcceptedView_Callback: " + << eid + << (vd.newMembers.contains(eid) ? " (new)" : ""); + } + + for (size_t j = 0; j < vd.departedMembers.size(); j++) + { + MaestroEID eid(vd.departedMembers[j]); + logger.debug() << "grpMemb_AcceptedView_Callback: " + << eid << " (departed)"; + } + } + + if (mFirstViewInstalled == 0) + { + // block_client(); + // mXferInProgress = true; + + Merge_Join_Callback(vd.myEndpID); + + mFirstViewInstalled = 1; + } + + // see who is new and will expect a state from us + if (vd.members.size() > 1 && vd.newMembers.size() > 0) + { + Maestro_Message state_msg; + + // here the application must fill in the fragment of the current state + // that is owned by itself + Merge_GetState_Callback(mMyView.myEndpID, state_msg); + + int token = MAESTRO_MERGE_STATE_CAST; + state_msg << token; + + Maestro_MsgSendView sendView = MAESTRO_MSG_SEND_CURRENT_VIEW; + Maestro_GroupMember::cast(state_msg, sendView); + + AVANGO_LOG(logger, logging::DEBUG, "grpMemb_AcceptedView_Callback: casted state.") + } + + // for all departed members tell the application to remove that state fragment + for (unsigned int k = 0; k < vd.departedMembers.size(); k++) + { + Merge_RemoveState_Callback(vd.departedMembers[k]); + } + + // Send out xfer-delayed messages. + mXferInProgress = false; + deliverDelayedMessages(); + + // Update private view data. + mMyView = vd; + + // Invoke user upcall. + Merge_AcceptedView_Callback(vd, msg); + + unblock_client(); + +#ifdef AVANGO_DEBUG + //dump("av::MaestroMerge::grpMemb_AcceptedView_Callback: leave"); +#endif +} + +void +av::MaestroMerge::grpMemb_ViewMsg_Callback(Maestro_GrpMemb_ViewData& viewData, + Maestro_Message &view_msg) +{ + MaestroMergeViewData vd(viewData); + + // Invoke user callback first, in case layers above want to push headers + // in the view message. + Merge_ViewMsg_Callback(vd, view_msg); + + vd.stateCounter = mMyView.stateCounter; + + // Push this layer's headers as the view message. + vd.splice_out(view_msg); + + // The new state transfer magic from roy + if (vd.myRank == 0) { + mValidStateGuro = 0; + mMaxStateCounter = -1; + mNumStates = 0; + } +} + +void +av::MaestroMerge::grpMemb_ViewStateInfo_Callback(Maestro_EndpID& origin, + Maestro_GrpMemb_ViewData& viewData, + Maestro_Message &view_msg, + Maestro_Message &next_view_msg, int &final) +{ + int upStateCounter; + + final = 0; + if (viewData.myRank == 0) + { + mNumStates++; + view_msg >> upStateCounter; + if (upStateCounter > mMaxStateCounter) + { + mValidStateGuro = 1; + mMaxStateCounter = upStateCounter; + mStateMsg = view_msg; + mStateGuro = origin; + } + if (mNumStates == viewData.nmembers) + { + next_view_msg <<= mStateMsg; + next_view_msg << mMaxStateCounter; + final = 1; + } + } +} + +void +av::MaestroMerge::Merge_Heartbeat_Callback(unsigned) +{} + +/********************** grpMemb_ReceiveCast_Callback ********************/ + +void +av::MaestroMerge::grpMemb_ReceiveCast_Callback(Maestro_EndpID &origin, Maestro_Message &msg) +{ + // ignore any casts before we properly joined the group + if (!mFirstViewInstalled) + { + AVANGO_LOG(logger, logging::INFO, "grpMemb_ReceiveCast_Callback: received cast before join.") + return; + } + + if (origin == mMyView.myEndpID) + { + // don't accept messages from myself + return; + } + + bool non_member = false; + if (!mMyView.members.contains(origin)) + { + // discard stray messages from departed members + AVANGO_LOG(logger, logging::INFO, "grpMemb_ReceiveCast_Callback: received cast from nonmember.") + + // return; + non_member = true; + } + + int mtype_int; + msg >> mtype_int; + Maestro_MergeMsgType mtype = Maestro_MergeMsgType(mtype_int); + + Maestro_EndpList dests; + + switch(mtype) + { + case MAESTRO_MERGE_CAST: + Merge_ReceiveCast_Callback(origin, msg); + if (non_member) + { + AVANGO_LOG(logger, logging::INFO, "grpMemb_ReceiveCast_Callback: was: MAESTRO_MERGE_CAST") + } + break; + + case MAESTRO_MERGE_STATE_CAST: + receive_state(origin, msg); + if (non_member) + { + AVANGO_LOG(logger, logging::INFO, "grpMemb_ReceiveCast_Callback: was: MAESTRO_STATE_CAST") + } + break; + + default: + AVANGO_LOG(logger, logging::ERROR, "grpMemb_ReceiveCast_Callback: Bad message type") + } +} + + +/*********************** grpMemb_ReceiveSend_Callback *******************/ + +void +av::MaestroMerge::grpMemb_ReceiveSend_Callback(Maestro_EndpID &origin, Maestro_Message &msg) +{ + int mtype_int; + msg >> mtype_int; + Maestro_MergeMsgType mtype = Maestro_MergeMsgType(mtype_int); + + switch (mtype) + { + + case MAESTRO_MERGE_SEND: + Merge_ReceiveSend_Callback(origin, msg); + break; + + default: + AVANGO_LOG(logger, logging::ERROR, "grpMemb_ReceiveSend_Callback: Bad message class") + } +} + +void +av::MaestroMerge::grpMemb_Block_Callback() +{ + block_client(); + mXferInProgress = true; +} + +void +av::MaestroMerge::grpMemb_Exit_Callback() +{ + Merge_Exit_Callback(); + mXferInProgress = false; + unblock_client(); +} + +/********************************* stuff ********************************/ + +void +av::MaestroMerge::block_client() +{ + AVANGO_LOG(logger, logging::TRACE, "block_client: enter") + + if (mFirstViewInstalled) + { + if (!mBlocked) + { + Merge_Block_Callback(); + mBlocked = true; + } + } + AVANGO_LOG(logger, logging::TRACE, "block_client: leave") +} + +void +av::MaestroMerge::unblock_client() +{ + AVANGO_LOG(logger, logging::TRACE, "unblock_client: enter") + if (mBlocked) + { + Merge_UnBlock_Callback(); + mBlocked = false; + } + AVANGO_LOG(logger, logging::TRACE, "unblock_client: leave") +} + +void +av::MaestroMerge::receive_state(Maestro_EndpID &origin, Maestro_Message &state_msg) +{ + AVANGO_LOG(logger, logging::DEBUG, boost::str(boost::format("av::Maestro_Merge::receive_state: received state from %1%") % origin)) + + // must deliver to application here + Merge_SetState_Callback(origin, state_msg); +} + + +/**************************** ViewData **********************************/ + +av::MaestroMergeViewData::MaestroMergeViewData(Maestro_GrpMemb_ViewData &gmView): + Maestro_GrpMemb_ViewData(gmView) +{} + +av::MaestroMergeViewData::MaestroMergeViewData() +{} + +void +av::MaestroMergeViewData::blend_in(Maestro_Message& msg) +{ + // fill in the merge specific data from the view message + msg >> stateCounter; +} + +void +av::MaestroMergeViewData::splice_out(Maestro_Message& msg) +{ + // extract the merge specific data into the new view message + msg << stateCounter; +} + +/************************* Delaying Message *****************************/ + +void +av::MaestroMerge::delayMessage(Maestro_Message &msg) +{ + DelayMsg dm; + dm._msg = msg; + dm._use_view = false; + dm._use_dest = false; + mDelayedMsgs.push_back(dm); +} + +void +av::MaestroMerge::delayMessage(Maestro_Message &msg, Maestro_MsgSendView &sendView) +{ + DelayMsg dm; + dm._msg = msg; + dm._view = sendView; + dm._use_view = true; + dm._use_dest = false; + mDelayedMsgs.push_back(dm); +} + +void +av::MaestroMerge::delayMessage(Maestro_EndpID &dest, Maestro_Message &msg) +{ + DelayMsg dm; + dm._msg = msg; + dm._dest = dest; + dm._use_view = false; + dm._use_dest = true; + mDelayedMsgs.push_back(dm); +} + +void +av::MaestroMerge::delayMessage(Maestro_EndpID &dest, Maestro_Message &msg, + Maestro_MsgSendView &sendView) +{ + DelayMsg dm; + dm._msg = msg; + dm._dest = dest; + dm._view = sendView; + dm._use_view = true; + dm._use_dest = true; + mDelayedMsgs.push_back(dm); +} + +void +av::MaestroMerge::deliverDelayedMessages() +{ + DelayMsgVec::iterator i; + for (i = mDelayedMsgs.begin(); i != mDelayedMsgs.end(); i++) { + DelayMsg& dm = *i; + if (dm._use_dest) { + if (dm._use_view) { + Maestro_GroupMember::send(dm._dest, dm._msg, dm._view); + } else { + Maestro_MsgSendView sendView = MAESTRO_MSG_SEND_CURRENT_VIEW; + Maestro_GroupMember::send(dm._dest, dm._msg, sendView); + } + } else { + if (dm._use_view) { + Maestro_GroupMember::cast(dm._msg, dm._view); + } else { + Maestro_MsgSendView sendView = MAESTRO_MSG_SEND_CURRENT_VIEW; + Maestro_GroupMember::cast(dm._msg, sendView); + } + } + } + mDelayedMsgs.clear(); +} + +const Maestro_EndpID& +av::MaestroMerge::eid() +{ + return mMyView.myEndpID; +} diff --git a/avango-core/src/avango/network/MaestroMerge.h b/avango-core/src/avango/network/MaestroMerge.h new file mode 100644 index 00000000..f4afe554 --- /dev/null +++ b/avango-core/src/avango/network/MaestroMerge.h @@ -0,0 +1,209 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_MAESTRO_MERGE_H) +#define AVANGO_MAESTRO_MERGE_H + +#include + +#include + +namespace av +{ + enum Maestro_MergeMsgType + { + MAESTRO_MERGE_CAST, + MAESTRO_MERGE_SEND, + MAESTRO_MERGE_STATE_CAST + }; + + struct MaestroMergeViewData : public Maestro_GrpMemb_ViewData + { + MaestroMergeViewData(); + MaestroMergeViewData(Maestro_GrpMemb_ViewData &gmView); + void blend_in(Maestro_Message& msg); + void splice_out(Maestro_Message& msg); + + int stateCounter; // counts the number of cast and send upcalls, added by Roy Friedman + }; + + typedef Maestro_GrpMemb_Options MaestroMergeOptions; + + /** + * MaestroMerge is a specialization of Maestro_GroupMember providing additional features + * for clients + * - State transfer callbacks + * - Automatic delaying of messages send during a state transfer + * - ... + */ + class MaestroMerge : public Maestro_GroupMember + { + public: + + MaestroMerge(MaestroMergeOptions &ops); + MaestroMerge(MaestroMerge& hMerge); + virtual ~MaestroMerge() {} + virtual MaestroMerge& operator=(MaestroMerge& hMerge); + + // Join the group. + virtual void join(); + + // Sending messages. + virtual void cast(Maestro_Message &msg); + virtual void cast(Maestro_Message &msg, Maestro_MsgSendView &sendView); + + virtual void send(Maestro_EndpID &dest, Maestro_Message &msg); + virtual void send(Maestro_EndpID &dest, Maestro_Message &msg, Maestro_MsgSendView &sendView); + + virtual void leave(); + + virtual const Maestro_EndpID& eid(); + + protected: + + /**************** Client-Server interface upcalls ***********************/ + + // State transfer callbacks + virtual void Merge_GetState_Callback(Maestro_EndpID&, Maestro_Message&) {} + virtual void Merge_SetState_Callback(Maestro_EndpID&, Maestro_Message&) {} + virtual void Merge_RemoveState_Callback(Maestro_EndpID&) {} + + // View callbacks + virtual void Merge_ViewMsg_Callback(MaestroMergeViewData &, /*OUT*/Maestro_Message &) {} + virtual void Merge_AcceptedView_Callback(MaestroMergeViewData&, Maestro_Message &) {} + + // Message callbacks + virtual void Merge_ReceiveCast_Callback(Maestro_EndpID &, Maestro_Message &) {} + virtual void Merge_ReceiveSend_Callback(Maestro_EndpID &, Maestro_Message &) {} + + // The group is blocked for a view change + virtual void Merge_Block_Callback() {} + virtual void Merge_UnBlock_Callback() {} + + // The member has joined the group and the first view is just beeing installed + + virtual void Merge_Join_Callback(Maestro_EndpID&) {} + + // The member has left the group + virtual void Merge_Exit_Callback() {} + + // Heartbeat callback + virtual void Merge_Heartbeat_Callback(unsigned time); + + private: + + int mFirstViewInstalled; + MaestroMergeViewData mMyView; + + bool mBlocked; + void block_client(); + void unblock_client(); + + void cast_state(); + void receive_state(Maestro_EndpID &origin, Maestro_Message &msg); + + // Added by Roy Friedman for new state xfer + int mValidStateGuro; + Maestro_Message mStateMsg; + int mMaxStateCounter; + Maestro_EndpID mStateGuro; + int mNumStates; + + int mXferInProgress; + + /**************************** Callbacks ************************************/ + + // View callbacks + void grpMemb_ViewMsg_Callback(Maestro_GrpMemb_ViewData &viewData, + /*OUT*/Maestro_Message &viewMsg); + void grpMemb_ViewStateInfo_Callback(Maestro_EndpID /*in*/&origin, + Maestro_GrpMemb_ViewData /*in*/&viewData, + Maestro_Message /*in*/&msg, + Maestro_Message /*out*/&next_view_msg, int /*out*/&final); + void grpMemb_AcceptedView_Callback(Maestro_GrpMemb_ViewData& viewData, Maestro_Message &msg); + + // Message Callbacks + void grpMemb_ReceiveCast_Callback(Maestro_EndpID &origin, Maestro_Message &msg); + void grpMemb_ReceiveSend_Callback(Maestro_EndpID &origin, Maestro_Message &msg); + + // The group is blocked for a view change + void grpMemb_Block_Callback(); + + // The member has left the group + void grpMemb_Exit_Callback(); + + // Heartbeat Callback: + void grpMemb_Heartbeat_Callback(unsigned time) { Merge_Heartbeat_Callback(time); } + + // delay messages sent during xfer + class DelayMsg + { + + public: + + DelayMsg() : + _use_view(false), + _use_dest(false) + {} + + DelayMsg(const DelayMsg& m) : + _msg((Maestro_Message&)m._msg), + _view(m._view), + _dest((Maestro_EndpID&)m._dest), + _use_view(m._use_view), + _use_dest(m._use_dest) + {} + + const DelayMsg& operator=(const DelayMsg& m) + { + _msg = (Maestro_Message&)m._msg; + _view = m._view; + _dest = (Maestro_EndpID&)m._dest; + _use_dest = m._use_dest; + _use_view = m._use_view; + return *this; + }; + + Maestro_Message _msg; + Maestro_MsgSendView _view; + Maestro_EndpID _dest; + bool _use_view; + bool _use_dest; + }; + + typedef std::vector DelayMsgVec; + DelayMsgVec mDelayedMsgs; + + void delayMessage(Maestro_Message &msg); + void delayMessage(Maestro_Message &msg, Maestro_MsgSendView &sendView); + void delayMessage(Maestro_EndpID &dest, Maestro_Message &msg); + void delayMessage(Maestro_EndpID &dest, Maestro_Message &msg, Maestro_MsgSendView &sendView); + void deliverDelayedMessages(); + + }; + +} // namespace av + +#endif // #if !defined(AVANGO_MAESTRO_MERGE_H) diff --git a/avango-core/src/avango/network/Msg.cpp b/avango-core/src/avango/network/Msg.cpp new file mode 100644 index 00000000..dd8e701a --- /dev/null +++ b/avango-core/src/avango/network/Msg.cpp @@ -0,0 +1,717 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/Msg.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace +{ + av::logging::Logger& logger(av::logging::Logger::getLogger("av::Msg")); +} + +av::Msg::Msg() + : mMsgType(relative), + mMsgBuffer(new MessageBuffer()) +{ +} + +av::Msg::Msg(MsgType newMsgType, boost::shared_ptr newBuffer) + : mMsgType(newMsgType), + mMsgBuffer(newBuffer) +{ +} + +av::Msg::~Msg() +{ +} + +size_t +av::Msg::getSize() +{ + return mMsgBuffer->size(); +} + +void +av::Msg::resize(size_t newSize) +{ + mMsgBuffer->resize(newSize); +} + + + +unsigned char* +av::Msg::getBuffer() +{ + return &(mMsgBuffer->operator[](0)); +} + +av::NetNode* +av::Msg::getNetNode() const +{ + return mNetNode; +} + +void +av::Msg::setNetNode(av::NetNode* netNode) +{ + mNetNode = netNode; +} + + +av::Msg +av::Msg::clone() const +{ + boost::shared_ptr copied_buffer(new MessageBuffer(*mMsgBuffer)); + return Msg(mMsgType, copied_buffer); +} + +// void* +void +av::Msg::push(const void* buffer, size_t bytes) +{ + const unsigned char* bufferMem = static_cast(buffer); + mMsgBuffer->insert(mMsgBuffer->end(), bufferMem, bufferMem+bytes); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (void*) [%1% byte%2%]") % bytes % (1 == bytes ? "" : "s"))) +} + +void +av::Msg::pop(void* buffer, size_t bytes) +{ + unsigned char* bufferMem = static_cast(buffer); + + AV_ASSERT(mMsgBuffer->size() >= bytes); + std::copy(mMsgBuffer->end() - bytes, mMsgBuffer->end(), bufferMem); + + mMsgBuffer->resize(mMsgBuffer->size() - bytes); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (void*) [%1% byte%2%]") % bytes % (1 == bytes ? "" : "s"))) +} + +// bool +void +av::av_pushMsg(av::Msg& msg, const bool& buf) +{ + int32_t b = (buf ? 1 : 0); + av_pushMsg(msg, b); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (bool) [%s]") % (buf ? "true" : "false"))) +} + +void +av::av_popMsg(av::Msg& msg, bool& buf) +{ + int32_t b; + av_popMsg(msg, b); + buf = (b == 0 ? false : true); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (bool) [%s]") % (buf ? "true" : "false"))) +} + +// int32_t +void +av::av_pushMsg(av::Msg& msg, const int32_t& buf) +{ + int32_t b; + XDRHandle xdr(&b, sizeof(b), XDR_ENCODE); + + xdr_int(xdr.getXDR(), (int32_t*) &buf); + + msg.push(&b, sizeof(b)); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (int32_t) [%1%]") % buf)); +} + +void +av::av_popMsg(av::Msg& msg, int32_t& buf) +{ + int32_t b; + XDRHandle xdr(&b, sizeof(b), XDR_DECODE); + + msg.pop((void*) &b, sizeof(b)); + + xdr_int(xdr.getXDR(), (int32_t*) &buf); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (int32_t) [%1%]") % buf)); +} + +// std::vector +void +av::av_pushMsg(av::Msg& msg, const std::vector& buf) +{ + std::vector tmpBuf(buf.size()); + XDRHandle xdr(&tmpBuf[0], sizeof(int32_t)*buf.size(), XDR_ENCODE) ; + + int32_t* arrayStart = const_cast(&buf[0]); // ugly, but necessary + + xdr_vector(xdr.getXDR(), reinterpret_cast(arrayStart), static_cast(buf.size()), sizeof(int32_t), + (xdrproc_t)xdr_int); + + msg.push(&tmpBuf[0], sizeof(int32_t)*buf.size()); + av_pushMsg(msg, static_cast(buf.size())); +} + +void +av::av_popMsg(av::Msg& msg, std::vector& buf) +{ + uint32_t arraySize; + av_popMsg(msg, arraySize); + + buf.resize(arraySize); + + std::vector tmpVec(arraySize); + XDRHandle xdr(&tmpVec[0], sizeof(int32_t) * arraySize, XDR_DECODE); + + msg.pop(&tmpVec[0], sizeof(int32_t)*arraySize); + + xdr_vector(xdr.getXDR(), reinterpret_cast(&buf[0]), static_cast(buf.size()), sizeof(int32_t), + (xdrproc_t)xdr_int); +} + + +// uint32_t +void +av::av_pushMsg(av::Msg& msg, const uint32_t& buf) +{ + uint32_t b; + XDRHandle xdr(&b, sizeof(b), XDR_ENCODE); + + xdr_u_int(xdr.getXDR(), (uint32_t*) &buf); + + msg.push(&b, sizeof(b)); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (uint32_t) [%1%]") % buf)); +} + +void +av::av_popMsg(av::Msg& msg, uint32_t& buf) +{ + uint32_t b; + XDRHandle xdr(&b, sizeof(b), XDR_DECODE); + + msg.pop(&b, sizeof(b)); + + xdr_u_int(xdr.getXDR(), &buf); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (uint32_t) [%1%]") % buf)); +} + +// std::vector +void +av::av_pushMsg(av::Msg& msg, const std::vector& buf) +{ + std::vector tmpVec(buf.size()); + XDRHandle xdr(&tmpVec[0], sizeof(uint32_t)*buf.size(), XDR_ENCODE); + + uint32_t* arrayStart = const_cast(&buf[0]); // ugly, but necessary + + xdr_vector(xdr.getXDR(), reinterpret_cast(arrayStart), static_cast(buf.size()), sizeof(uint32_t), + (xdrproc_t)xdr_u_int); + + msg.push(&tmpVec[0], sizeof(uint32_t)*buf.size()); + av_pushMsg(msg, static_cast(buf.size())); +} + +void +av::av_popMsg(av::Msg& msg, std::vector& buf) +{ + uint32_t arraySize; + av_popMsg(msg, arraySize); + + buf.resize(arraySize); + + std::vector tmpVec(arraySize); + + XDRHandle xdr(&tmpVec[0], sizeof(uint32_t)*arraySize, XDR_DECODE); + msg.pop(&tmpVec[0], sizeof(uint32_t)*arraySize); + + xdr_vector(xdr.getXDR(), reinterpret_cast(&buf[0]), static_cast(buf.size()), sizeof(uint32_t), + (xdrproc_t)xdr_u_int); +} + + +// int64_t +void +av::av_pushMsg(av::Msg& msg, const int64_t& buf) +{ + int64_t b; + XDRHandle xdr(&b, sizeof(b), XDR_ENCODE); + + xdr_longlong_t(xdr.getXDR(), (int64_t*) &buf); + + msg.push(&b, sizeof(b)); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (int64_t) [%1%]") % buf)); +} + +void +av::av_popMsg(av::Msg& msg, int64_t& buf) +{ + int64_t b; + XDRHandle xdr(&b, sizeof(b), XDR_DECODE); + + msg.pop(&b, sizeof(b)); + + xdr_longlong_t(xdr.getXDR(), (int64_t*) &buf); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (int64_t) [%1%]") % buf)); +} + +// std::vector +void +av::av_pushMsg(av::Msg& msg, const std::vector& buf) +{ + std::vector tmpVec(buf.size()); + XDRHandle xdr(&tmpVec[0], sizeof(int64_t)*buf.size(), XDR_ENCODE); + + int64_t* arrayStart = const_cast(&buf[0]); // ugly, but necessary + + xdr_vector(xdr.getXDR(), reinterpret_cast(arrayStart), static_cast(buf.size()), sizeof(int64_t), + (xdrproc_t)xdr_longlong_t); + + msg.push(&tmpVec[0], sizeof(int64_t)*buf.size()); + av_pushMsg(msg, static_cast(buf.size())); +} + +void +av::av_popMsg(av::Msg& msg, std::vector& buf) +{ + uint32_t arraySize; + av_popMsg(msg, arraySize); + + buf.resize(arraySize); + + std::vector tmpVec(arraySize); + XDRHandle xdr(&tmpVec[0], sizeof(int64_t)*arraySize, XDR_DECODE); + + msg.pop(&tmpVec[0], sizeof(int64_t)*arraySize); + + xdr_vector(xdr.getXDR(), reinterpret_cast(&buf[0]), static_cast(buf.size()), sizeof(int64_t), + (xdrproc_t)xdr_longlong_t); +} + + +// uint64_t +void +av::av_pushMsg(av::Msg& msg, const uint64_t& buf) +{ + uint64_t b; + XDRHandle xdr(&b, sizeof(b), XDR_ENCODE); + + xdr_u_longlong_t(xdr.getXDR(), (uint64_t*) &buf); + + msg.push(&b, sizeof(b)); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (uint64_t) [%1%]") % buf)); +} + +void +av::av_popMsg(av::Msg& msg, uint64_t& buf) +{ + uint64_t b; + XDRHandle xdr(&b, sizeof(b), XDR_DECODE); + + msg.pop(&b, sizeof(b)); + + xdr_u_longlong_t(xdr.getXDR(), (uint64_t*) &buf); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (uint64_t) [%1%]") % buf)); +} + +// std::vector +void +av::av_pushMsg(av::Msg& msg, const std::vector& buf) +{ + std::vector tmpVec(buf.size()); + + XDRHandle xdr(&tmpVec[0], sizeof(uint64_t)*buf.size(), XDR_ENCODE); + + uint64_t* arrayStart = const_cast(&buf[0]); // ugly, but necessary + + xdr_vector(xdr.getXDR(), reinterpret_cast(arrayStart), static_cast(buf.size()), sizeof(uint64_t), + (xdrproc_t)xdr_u_longlong_t); + + msg.push(&tmpVec[0], sizeof(uint64_t)*buf.size()); + av_pushMsg(msg, static_cast(buf.size())); +} + +void +av::av_popMsg(av::Msg& msg, std::vector& buf) +{ + uint32_t arraySize; + av_popMsg(msg, arraySize); + + buf.resize(arraySize); + + std::vector tmpVec(arraySize); + + XDRHandle xdr(&tmpVec[0], sizeof(uint64_t)*arraySize, XDR_DECODE); + msg.pop(&tmpVec[0], sizeof(uint64_t)*arraySize); + + xdr_vector(xdr.getXDR(), reinterpret_cast(&buf[0]), static_cast(buf.size()), sizeof(uint64_t), + (xdrproc_t)xdr_u_longlong_t); +} + + +// float +void +av::av_pushMsg(av::Msg& msg, const float& buf) +{ + float b; + XDRHandle xdr(&b, sizeof(b), XDR_ENCODE); + + xdr_float(xdr.getXDR(), (float*) &buf); + + msg.push(&b, sizeof(b)); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (float) [%1%]") % buf)); +} + +void +av::av_popMsg(av::Msg& msg, float& buf) +{ + float b; + XDRHandle xdr(&b, sizeof(b), XDR_DECODE); + + msg.pop(&b, sizeof(b)); + + xdr_float(xdr.getXDR(), &buf); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (float) [%1%]") % buf)); +} + +// std::vector +void +av::av_pushMsg(av::Msg& msg, const std::vector& buf) +{ + std::vector tmpVec(buf.size()); + + XDRHandle xdr(&tmpVec[0], sizeof(float)*buf.size(), XDR_ENCODE); + + float* arrayStart = const_cast(&buf[0]); // ugly, but necessary + + xdr_vector(xdr.getXDR(), (char*)arrayStart, static_cast(buf.size()), sizeof(float), (xdrproc_t)xdr_float); + + msg.push(&tmpVec[0], sizeof(float)*buf.size()); + av_pushMsg(msg, static_cast(buf.size())); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (vector) [%1%]") % buf.size())) +} + +void +av::av_popMsg(av::Msg& msg, std::vector& buf) +{ + uint32_t arraySize; + av_popMsg(msg, arraySize); + + buf.resize(arraySize); + + std::vector tmpVec(arraySize); + + XDRHandle xdr(&tmpVec[0], sizeof(float)*arraySize, XDR_DECODE); + + msg.pop(&tmpVec[0], sizeof(float)*arraySize); + + xdr_vector(xdr.getXDR(), (char*)&buf[0], static_cast(buf.size()), sizeof(float), (xdrproc_t)xdr_float); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (vector) [%1%]") % buf.size())) +} + + +// double +void +av::av_pushMsg(av::Msg& msg, const double& buf) +{ + double b; + XDRHandle xdr(&b, sizeof(b), XDR_ENCODE); + + xdr_double(xdr.getXDR(), (double*)&buf); + + msg.push(&b, sizeof(b)); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (double) [%1%]") % buf)) +} + +void +av::av_popMsg(av::Msg& msg, double& buf) +{ + double b; + XDRHandle xdr(&b, sizeof(b), XDR_DECODE); + + msg.pop(&b, sizeof(b)); + + xdr_double(xdr.getXDR(), &buf); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (double) [%1%]") % buf)) +} + +// std::vector +void +av::av_pushMsg(av::Msg& msg, const std::vector& buf) +{ + std::vector tmpVec(buf.size()); + + XDRHandle xdr(&tmpVec[0], sizeof(double)*buf.size(), XDR_ENCODE); + + double* arrayStart = const_cast(&buf[0]); // ugly, but necessary + + xdr_vector(xdr.getXDR(), reinterpret_cast(arrayStart), static_cast(buf.size()), sizeof(double), + (xdrproc_t)xdr_double); + + msg.push(&tmpVec[0], sizeof(double)*buf.size()); + av_pushMsg(msg, static_cast(buf.size())); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (vector) [%1%]") % buf.size())) +} + +void +av::av_popMsg(av::Msg& msg, std::vector& buf) +{ + uint32_t arraySize; + av_popMsg(msg, arraySize); + + buf.resize(arraySize); + + std::vector tmpVec(arraySize); + + XDRHandle xdr(&tmpVec[0], sizeof(double)*arraySize, XDR_DECODE); + + msg.pop(&tmpVec[0], sizeof(double)*arraySize); + + xdr_vector(xdr.getXDR(), reinterpret_cast(&buf[0]), static_cast(buf.size()), sizeof(double), + (xdrproc_t)xdr_double); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (vector) [%1%]") % buf.size())) +} + +// AnyLink +void +av::av_pushMsg(av::Msg& msg, const AnyLink& buf) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (AnyLink) []"))); + + if (!buf.isValid()) + { + NetID id(NetID::nullID()); + av_pushMsg(msg, id); + return; + } + + Distributed* obj = dynamic_cast(buf.getBasePtr()); + AV_ASSERT(obj); + + if (!obj->isDistributed()) + { + NetID id(NetID::nullID()); + av_pushMsg(msg, id); + return; + } + + NetID id(obj->netID()); + av_pushMsg(msg, id); +} + +void +av::av_popMsg(av::Msg& msg, AnyLink& buf) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (AnyLink) []"))); + + NetID id; + av_popMsg(msg, id); + if (id.isNull()) + { + buf.clear(); + return; + } + + AV_ASSERT(msg.getNetNode()); + Link obj; + + if (!msg.getNetNode()->lookup(id, obj)) + { + buf.clear(); + return; + } + + if (!obj.isValid() || !buf.setBasePtr(obj.getBasePtr())) + { + // this object is either not there or of wrong type. + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("pop: object is either not there or of wrong type."))); + buf.clear(); + } +} + +// Type +void +av::av_pushMsg(av::Msg& msg, const Type& buf) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (Type) [%1%]") % buf.getName().c_str())) + + av_pushMsg(msg, buf.getName()); +} + +void +av::av_popMsg(av::Msg& msg, Type& buf) +{ + std::string type_name; + av_popMsg(msg, type_name); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (Type) [%1%]") % type_name)) + + buf = Type::getByName(type_name); + + if (!buf.isBad()) + { + // type is known, everything is fine + return; + } else + { + // we don't know this type + AVANGO_LOG(logger, logging::ERROR, boost::str(boost::format("pop: unable to initialize type '%1%'; what else can I do?") % type_name)) + return; + } +} + +// Field +void +av::av_pushMsg(av::Msg& msg, av::Field* field) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (Field*) [%1%,%2%,%3%,%4%]") + % field + % field->getTypeId().getName() + % field->getName() + % field->getIndex())) + + AV_ASSERT(field); + + field->push(msg); +} + +void +av::av_popMsg(av::Msg& msg, av::Field* field) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (Field*) [%1%,%2%,%3%,%4%]") + % field + % field->getTypeId().getName() + % field->getName() + % field->getIndex())) + + AV_ASSERT(field); + field->pop(msg); + +} + +// Distributed +void +av::av_pushMsg(av::Msg& msg, av::Distributed* distrObj) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (Distributed*) [%1%,%2%]") + % distrObj + % distrObj->getTypeId().getName())) + + AV_ASSERT(distrObj); + distrObj->push(msg); +} + +void +av::av_popMsg(av::Msg& msg, av::Distributed* distrObj) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (Distributed*) [%1%,%2%]") + % distrObj + % distrObj->getTypeId().getName())) + + AV_ASSERT(distrObj); + distrObj->pop(msg); +} + + +// std::string +void +av::av_pushMsg(av::Msg& msg, const std::string& str) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (std::string) [%1%]") % str)); + + uint32_t length = str.size(); + if (length) + { + msg.push(str.c_str(), length); + } + av_pushMsg(msg, length); +} + +void +av::av_popMsg(av::Msg& msg, std::string& str) +{ + uint32_t length = 0; + av_popMsg(msg, length); + if (length) + { + char* buf = new char[length]; + boost::scoped_array bufHandler(buf); + msg.pop(buf, length); + str.assign(buf, length); + } + else + { + str.assign(""); + } + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (std::string) [%1%]") % str)); +} + +// NetID +void +av::av_pushMsg(av::Msg& msg, const av::NetID& id) +{ + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("push: (NetID) [%1%]") % id)); + + av_pushMsg(msg, id.getEID()); + av_pushMsg(msg, id.getNum()); +} + +void +av::av_popMsg(av::Msg& msg, av::NetID& id) +{ + int number = 0; + std::string eid; + bool well_known = false; + + av_popMsg(msg, number); + av_popMsg(msg, eid); + + id.set(eid, number); + + AVANGO_LOG(logger, logging::TRACE, boost::str(boost::format("pop: (NetID) [%1%]") % id)); +} diff --git a/avango-core/src/avango/network/NetGroup.cpp b/avango-core/src/avango/network/NetGroup.cpp new file mode 100644 index 00000000..c295ebce --- /dev/null +++ b/avango-core/src/avango/network/NetGroup.cpp @@ -0,0 +1,228 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "NetGroup.h" + +#include + + +#include +#include + +#include +#include +#include +#include + +#include + +namespace +{ + av::logging::Logger& logger(av::logging::Logger::getLogger("av::NetGroup")); +} + +// create a new group member +av::NetGroup::NetGroup(NetNode* net_node, Maestro_ClSv_Options &options) + : MaestroMerge(options), + mNetNode(net_node), + mUpcallSerializer() +{ + + if (!net_node) + { + throw std::invalid_argument("net_node may not be 0"); + } +} + +// destroy this group member and leave the group +av::NetGroup::~NetGroup() +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::~NetGroup: ") +} + +av::UpcallSerializer& +av::NetGroup::upcallSerializer() +{ + return mUpcallSerializer; +} + +void +av::NetGroup::cast(av::Msg& msg) +{ + Maestro_Message maestro_msg; + maestro_msg.write(msg.getBuffer(), msg.getSize()); + MaestroMerge::cast(maestro_msg); +} + +void +av::NetGroup::send(const std::string &destEID, av::Msg& msg) +{ + Maestro_Message maestro_msg; + maestro_msg.write(msg.getBuffer(), msg.getSize()); + + hot_endpt_t endpID; + ::strncpy(endpID.name, destEID.c_str(), HOT_ENDP_MAX_NAME_SIZE); + Maestro_EndpID maestro_endpID(endpID); + MaestroMerge::send(maestro_endpID, maestro_msg); +} + +void +av::NetGroup::Merge_Join_Callback(Maestro_EndpID& /*myeid*/) +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_Join_Callback: ") + // maestro_eid dummy(myeid); + // _net_node->joined(dummy); + + //fp_join_upcall* join = new fp_join_upcall(myeid); + //_upcall_serializer.make_upcall(join); +} + +// State transfer callbacks +void +av::NetGroup::Merge_SetState_Callback(Maestro_EndpID& fragment, Maestro_Message& stateMessage) +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_SetState_Callback: ") + + // _net_node->set_state_fragment(fragment, state_message); + // _net_node->queue_state_fragment(fragment, state_message); + + Msg av_msg; + av_msg.resize(stateMessage.getPos()); + stateMessage.read(av_msg.getBuffer(), av_msg.getSize()); + + boost::shared_ptr set_state(new SetStateUpcall(fragment.getHotEndpt().name, av_msg)); + mUpcallSerializer.makeUpcall(set_state); +} + +void +av::NetGroup::Merge_GetState_Callback(Maestro_EndpID& fragment, Maestro_Message& stateMessage) +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_GetState_Callback: ") + + boost::shared_ptr get_state(new GetStateUpcall(fragment.getHotEndpt().name)); + + mUpcallSerializer.makeUpcall(get_state); + + stateMessage.reset(); + + stateMessage.write(get_state->stateMsg().getBuffer(), get_state->stateMsg().getSize()); + +} + +void +av::NetGroup::Merge_RemoveState_Callback(Maestro_EndpID& fragment) +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_RemoveState_Callback: ") + + boost::shared_ptr remove_state(new RemoveStateUpcall(fragment.getHotEndpt().name)); + mUpcallSerializer.makeUpcall(remove_state); +} + +// callbacks for messages +void +av::NetGroup::Merge_ReceiveCast_Callback(Maestro_EndpID &/*origin*/, Maestro_Message &msg) +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_ReceiveCast_Callback: ") + + // _net_node->receive_message(origin, msg); + Msg av_msg; + av_msg.resize(msg.getPos()); + msg.read(av_msg.getBuffer(), av_msg.getSize()); + + boost::shared_ptr message(new MessageUpcall(av_msg)); + mUpcallSerializer.makeUpcall(message); +} + +void +av::NetGroup::Merge_ReceiveSend_Callback(Maestro_EndpID &/*origin*/, Maestro_Message &msg) +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_ReceiveSend_Callback: ") + + // _net_node->receive_message(origin, msg); + Msg av_msg; + av_msg.resize(msg.getPos()); + msg.read(av_msg.getBuffer(), av_msg.getSize()); + + boost::shared_ptr message(new MessageUpcall(av_msg)); + mUpcallSerializer.makeUpcall(message); +} + +// view change callbacks +void +av::NetGroup::Merge_AcceptedView_Callback(MaestroMergeViewData &view_data, Maestro_Message &msg) +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_AcceptedView_Callback: ") + + Msg av_msg; + av_msg.resize(msg.getPos()); + msg.read(av_msg.getBuffer(), av_msg.getSize()); + + std::vector members; + for (int member = 0; member < view_data.members.size(); ++member) { + members.push_back(view_data.members[member].getHotEndpt().name); + } + + std::vector new_members; + for (int new_member = 0; new_member < view_data.newMembers.size(); ++new_member) { + new_members.push_back(view_data.newMembers[new_member].getHotEndpt().name); + } + + std::vector departed_members; + for (int departed_member = 0; departed_member < view_data.departedMembers.size(); ++departed_member) { + departed_members.push_back(view_data.departedMembers[departed_member].getHotEndpt().name); + } + + + boost::shared_ptr view(new AcceptedViewUpcall(members, new_members, departed_members, av_msg)); + mUpcallSerializer.makeUpcall(view); +} + +void +av::NetGroup::Merge_Block_Callback() +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_Block_Callback: ") + + boost::shared_ptr block(new BlockUpcall); + mUpcallSerializer.makeUpcall(block); +} + +void +av::NetGroup::Merge_UnBlock_Callback() +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_UnBlock_Callback: ") + + boost::shared_ptr unblock(new UnblockUpcall); + mUpcallSerializer.makeUpcall(unblock); +} + +// The member has left the group +void +av::NetGroup::Merge_Exit_Callback() +{ + AVANGO_LOG(logger, logging::TRACE, "av::NetGroup::Merge_Exit_Callback: ") + + boost::shared_ptr exit(new ExitUpcall); + mUpcallSerializer.makeUpcall(exit); +} diff --git a/avango-core/src/avango/network/NetGroup.h b/avango-core/src/avango/network/NetGroup.h new file mode 100644 index 00000000..22f20f4d --- /dev/null +++ b/avango-core/src/avango/network/NetGroup.h @@ -0,0 +1,103 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_NETGROUP_H) +#define AVANGO_NETGROUP_H + +#include + +// #include +#include + +#include "MaestroMerge.h" +#include "UpcallSerializer.h" + +class Maestro_ClSv_Options; + +namespace av +{ + // + // NetGroup -- interface to ensemble, contain all Maestro include files, + // bridge the process barrier for the callbacks. + // + + // This class implements the ensemble group member + + class NetGroup : public MaestroMerge { + public: + + // create a new group member and join the named group + NetGroup(NetNode* netNode, Maestro_ClSv_Options &options); + + // destroy this group member and leave the group + ~NetGroup(); + + UpcallSerializer& upcallSerializer(); + + // Sending messages. + virtual void cast(Msg &msg); + + virtual void send(const std::string &destEID, Msg &msg); + + private: + + // the NetNode which created us + NetNode* mNetNode; + + UpcallSerializer mUpcallSerializer; + + // State transfer callbacks + virtual void Merge_GetState_Callback(Maestro_EndpID& fragment, Maestro_Message& state_message); + virtual void Merge_SetState_Callback(Maestro_EndpID& fragment, Maestro_Message& state_message); + virtual void Merge_RemoveState_Callback(Maestro_EndpID& fragment); + + // Message callbacks: + virtual void Merge_ReceiveCast_Callback(Maestro_EndpID &origin, Maestro_Message &msg); + virtual void Merge_ReceiveSend_Callback(Maestro_EndpID &origin, Maestro_Message &msg); + + // view change callbacks + virtual void Merge_AcceptedView_Callback(MaestroMergeViewData&, Maestro_Message&); + virtual void Merge_Block_Callback(); + virtual void Merge_UnBlock_Callback(); + + // The member has left the group: + virtual void Merge_Join_Callback(Maestro_EndpID& myeid); + + // The member has left the group: + virtual void Merge_Exit_Callback(); + + private: + + // declared but never defined + //NetGroup(); + //NetGroup(const NetGroup&); + //const NetGroup& operator= (const NetGroup&); + + }; + +} // namespace av + +#endif // #if !defined(AVANGO_NETGROUP_H) + diff --git a/avango-core/src/avango/network/NetID.cpp b/avango-core/src/avango/network/NetID.cpp new file mode 100644 index 00000000..20c33f79 --- /dev/null +++ b/avango-core/src/avango/network/NetID.cpp @@ -0,0 +1,120 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/NetID.h" + +#include + +/* static */ const int av::NetID::sNetGroupContainerHolder = -202; +/* static */ const int av::NetID::sNetGroupRootNode = -201; +/* static */ const int av::NetID::sWellKnownBase = -100; + +av::NetID::NetID() +{ + setNull(); +} + +av::NetID::NetID(const std::string& eid, int number) +{ + set(eid, number); +} + +av::NetID::NetID(const av::NetID& ni) +{ + set(ni.mCreator, ni.mNumber); +} + +av::NetID::~NetID() +{} + +av::NetID& +av::NetID::operator=(const NetID& ni) +{ + set(ni.mCreator, ni.mNumber); + return *this; +} + +bool +av::NetID::operator==(const NetID& ni) const +{ + return + (mNumber == ni.mNumber) && + (mCreator == ni.mCreator); +} + +void +av::NetID::set(const std::string& eid, int number) +{ + mCreator = eid; + mNumber = number; +} + +int +av::NetID::getNum() const +{ + return mNumber; +} + +const std::string& +av::NetID::getEID() const +{ + return mCreator; +} + +void +av::NetID::setNull() +{ + mNumber = -1; +} + +bool +av::NetID::isNull() const +{ + return mNumber == -1; +} + +av::NetID +av::NetID::nullID() +{ + return NetID(); +} + +bool +av::NetID::isWellKnown() const +{ + return mNumber <= sWellKnownBase; +} + +std::ostream& av::operator<< (std::ostream& os, const NetID& id) +{ + if (id.isNull()) { + os << ""; + } else if (id.isWellKnown()) { + os << id.mCreator << "#<" << id.mNumber << ">"; + } else { + os << id.mCreator << "#" << id.mNumber; + } + return os; +} diff --git a/avango-core/src/avango/network/NetInfo.cpp b/avango-core/src/avango/network/NetInfo.cpp new file mode 100644 index 00000000..cb7d9452 --- /dev/null +++ b/avango-core/src/avango/network/NetInfo.cpp @@ -0,0 +1,103 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include "avango/NetInfo.h" + +// includes, system + +#include + +// includes, project + +#include + +#include + +// internal unnamed namespace + +namespace { + av::Logger &logger(av::getLogger("av::NetInfo")); +} // namespace { + +av::NetInfo::NetInfo(const NetID& a, const NetNode* b) + : mId (a), + mNode (const_cast (b)) +{ +#if AVANGO_DEBUG + LOG_TRACE(logger) << "NetInfo::NetInfo: " + << " @" << this + << " id: " << mId + << " node: @" << mNode; +#endif +} + +av::NetInfo::~NetInfo() +{ +#if AVANGO_DEBUG + LOG_TRACE(logger) << "NetInfo::~NetInfo: " + << " @" << this + << " id: " << mId + << " node: @" << mNode; +#endif +} + +const av::NetID& +av::NetInfo::getId() const +{ +#if AVANGO_DEBUG + LOG_TRACE(logger) << "NetInfo::get_id: " + << " @" << this + << " id: " << mId + << " node: @" << mNode; +#endif + + return mId; +} + +const av::NetNode* +av::NetInfo::getNode() const +{ +#if AVANGO_DEBUG + LOG_TRACE(logger) << "NetInfo::get_node: " + << " @" << this + << " id: " << mId + << " node: @" << mNode; +#endif + return mNode; +} + +av::NetNode* +av::NetInfo::getNode() +{ +#if AVANGO_DEBUG + LOG_TRACE(logger) << "NetInfo::get_node: " + << " @" << this + << " id: " << mId + << " node: @" << mNode; +#endif + return mNode; +} diff --git a/avango-core/src/avango/network/NetLock.cpp b/avango-core/src/avango/network/NetLock.cpp new file mode 100644 index 00000000..4901bfbd --- /dev/null +++ b/avango-core/src/avango/network/NetLock.cpp @@ -0,0 +1,84 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include + +AV_FC_DEFINE(av::NetLock); + +av::NetLock::NetLock() + : mRelease(false), mRequest(false) +{ + AV_FC_ADD_FIELD(Request, ""); + AV_FC_ADD_FIELD(Granted, ""); + AV_FC_ADD_FIELD(Release, ""); + + getTypeId().setDistributable(true); + +} + +av::NetLock::~NetLock() +{} + +/*static*/ void +av::NetLock::initClass() +{ + if(!isTypeInitialized()) + { + FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, + av::NetLock, + true); + } +} + +void +av::NetLock::fieldHasChanged(const av::Field& field) +{ + if (&field == &Request) { + mRequest = true; + } else if (&field == &Release) { + mRelease = true; + } +} + +void +av::NetLock::evaluate() +{ + if (mRequest) { + if (Granted.getValue().empty()) { + Granted.setValue(Request.getValue()); + } + mRequest = false; + } + if (mRelease) { + if (Granted.getValue() == Release.getValue()) { + Granted.setValue(""); + } + mRelease = false; + } +} + + diff --git a/avango-core/src/avango/network/NetMap.cpp b/avango-core/src/avango/network/NetMap.cpp new file mode 100644 index 00000000..2c578043 --- /dev/null +++ b/avango-core/src/avango/network/NetMap.cpp @@ -0,0 +1,378 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/NetMap.h" + +#include + +#include +#include + +#include "Helper.h" + +#define FP_NET_DEBUG 3 +#undef FP_NET_DEBUG + +namespace +{ + av::Logger& logger(av::getLogger("av::NetMap")); +} + +av::NetMap::NetMap() + : mEIDMap() +{} + +av::NetMap::~NetMap() +{} + +void +av::NetMap::addSlot(const std::string& eid) +{ +#if FP_NET_DEBUG > 1 + std::cout << "NetMap::add_slot: " + << "for eid: " + << eid + << std::endl; +#endif + + // make sure it doesn't already exist + if (mEIDMap.find(eid) == mEIDMap.end()) + mEIDMap[eid] = IntDstMap(); + else + logger.warn() << "add_slot: '%s' already added", eid.c_str(); +} + +void +av::NetMap::removeSlot(const std::string& eid) +{ +#if FP_NET_DEBUG > 1 + std::cout << "NetMap::remove_slot: " + << "for eid: " + << eid + << std::endl; +#endif + + // make sure it's there + EIDMapMap::iterator i = mEIDMap.find(eid); + if (i != mEIDMap.end()) + mEIDMap.erase(i); + else + logger.warn() << "remove_slot: '%s' not yet added", eid.c_str(); +} + +bool +av::NetMap::slotExists(const std::string& eid) const +{ + return (mEIDMap.find(eid) != mEIDMap.end()); +} + +void +av::NetMap::registerObj(const av::Link& obj) +{ +#if FP_NET_DEBUG > 1 + std::cout << "NetMap::register_obj: " + << "id: " + << obj->netID() + << std::endl; +#endif + + AV_ASSERT(obj->isDistributed()); + const std::string& eid(obj->netID().getEID()); + int num(obj->netID().getNum()); + + // make sure the slot exists, but ... + EIDMapMap::iterator i = mEIDMap.find(eid); + + if (i == mEIDMap.end()) { + std::cout << "NetMap::register_obj: " + << "slot not found for: " + << obj->netID() + << std::endl; + } + + // ... the object doesn't. + IntDstMap& dst_map = (*i).second; + + + if (dst_map.find(num) != dst_map.end()) { + logger.warn() << "register_obj: " + << "'%s' of type '%s' cannot be registered twice!", + getName(obj), obj->getTypeId().getName().c_str(); + + return; + } + + // insert the object + dst_map[num] = obj; +} + +void +av::NetMap::unregisterObj(const av::Link& obj) +{ +#if FP_NET_DEBUG > 1 + std::cout << "NetMap::unregister_obj: " + << "id: " + << obj->netID() + << std::endl; +#endif + + // assert(obj->is_distributed()); + if (!obj->isDistributed()) { + logger.info() << "unregister_obj: " + << "'%s' of type '%s' not yet distributed!", + getName(obj), obj->getTypeId().getName().c_str(); + + return; + } + + const std::string& eid = obj->netID().getEID(); + int num = obj->netID().getNum(); + + // make sure the slot exists, and ... + EIDMapMap::iterator i = mEIDMap.find(eid); + + if (mEIDMap.end() != i) { + // the object does also! + IntDstMap& dst_map = (*i).second; + IntDstMap::iterator j = dst_map.find(num); + + if (dst_map.end() != j) { + // remove the object + dst_map.erase(j); + } else { + logger.warn() << "unregister_obj: " + << "'%s' of type '%s' does not exist in destination map!", + getName(obj), obj->getTypeId().getName().c_str(); + } + } else { + logger.info() << "unregister_obj: " + << "'%s' of type '%s' does not exist!", + getName(obj), obj->getTypeId().getName().c_str(); + } +} + +bool +av::NetMap::lookup(const av::NetID& id, av::Link& result) const +{ + // return a single object, object not found is illegal + const std::string& eid = id.getEID(); + int num = id.getNum(); + + // make sure the slot exists, and ... + EIDMapMap::const_iterator i = mEIDMap.find(eid); + if (i == mEIDMap.end()) { +#if FP_NET_DEBUG > 2 + std::cout << "NetMap::lookup: " + << "failed for id: " + << id + << std::endl; +#endif + return false; + } + + // the object does also! + const IntDstMap& dst_map = (*i).second; + IntDstMap::const_iterator j = dst_map.find(num); + if (j == dst_map.end()) { +#if FP_NET_DEBUG > 2 + std::cout << "NetMap::lookup: " + << "failed for id: " + << id + << std::endl; +#endif + return false; + } + +#if FP_NET_DEBUG > 2 + std::cout << "NetMap::lookup: " + << "succeeded for id: " + << id + << std::endl; +#endif + + result = (*j).second; + return true; +} + +bool +av::NetMap::lookup(const std::string& eid, std::vector >& result) const +{ + // return all objects with the matching eid + // make sure the slot exists, and ... + EIDMapMap::const_iterator i = mEIDMap.find(eid); + if (i == mEIDMap.end()) { +#if FP_NET_DEBUG > 2 + std::cout << "NetMap::lookup: " + << "failed for eid: " + << eid + << std::endl; +#endif + return false; + } + + // ... copy all objects into a std::vector + const IntDstMap& dst_map = (*i).second; + IntDstMap::const_iterator j; + result.clear(); + for (j=dst_map.begin(); j!=dst_map.end(); ++j) + result.push_back((*j).second); + +#if FP_NET_DEBUG > 2 + std::cout << "NetMap::lookup: " + << "succeeded for eid: " + << eid + << std::endl; +#endif + + return true; +} + +bool +av::NetMap::lookupExcept(const std::string& eid, std::vector >& result) const +{ + // return all objects except the ones with the matching eid + // make sure the slot exists, and ... + EIDMapMap::const_iterator not_this = mEIDMap.find(eid); + if (not_this == mEIDMap.end()) { +#if FP_NET_DEBUG > 2 + std::cout << "NetMap::lookup_except: " + << "excepted eid not there anyway: " + << eid + << std::endl; +#endif + return false; + } + + // ... copy all objects into a std::vector + result.clear(); + EIDMapMap::const_iterator i; + for (i = mEIDMap.begin(); i != mEIDMap.end(); ++i) { + if (i != not_this) { + const IntDstMap& dst_map = (*i).second; + IntDstMap::const_iterator j; + for (j=dst_map.begin(); j!=dst_map.end(); j++) + result.push_back((*j).second); + } + } +#if FP_NET_DEBUG > 2 + std::cout << "NetMap::lookup_except: " + << "succeeded for eid: " + << eid + << std::endl; +#endif + + return true; +} + +bool +av::NetMap::lookup(std::vector >& result) const +{ + result.clear(); + EIDMapMap::const_iterator i; + for (i=mEIDMap.begin(); i!=mEIDMap.end(); i++) { + const IntDstMap& dst_map = (*i).second; + IntDstMap::const_iterator j; + for (j=dst_map.begin(); j!=dst_map.end(); j++) + result.push_back((*j).second); + } + return true; +} + +void +av::NetMap::removeAllSlots() +{ + mEIDMap.clear(); +} + +void +av::NetMap::removeAllSlotsExcept(const std::string& eid) +{ + EIDMapMap::const_iterator i = mEIDMap.find(eid); + AV_ASSERT(i != mEIDMap.end()); + IntDstMap dst_map = (*i).second; // hardcore copy + mEIDMap.clear(); + mEIDMap[eid] = dst_map; // hardcore copy +} + +void +av::NetMap::emptyAllSlots() +{ + EIDMapMap::iterator i; + for (i=mEIDMap.begin(); i!=mEIDMap.end(); i++) { + IntDstMap& dst_map = (*i).second; + dst_map.clear(); + } +} + +void +av::NetMap::emptyAllSlotsExcept(const std::string& eid) +{ + EIDMapMap::iterator i = mEIDMap.find(eid); + AV_ASSERT(i != mEIDMap.end()); + + for (i= mEIDMap.begin(); i!= mEIDMap.end(); i++) + if (eid != (*i).first) { + IntDstMap& dst_map = (*i).second; + dst_map.clear(); + } +} + +void +av::NetMap::emptySlot(const std::string& eid) +{ + EIDMapMap::iterator i = mEIDMap.find(eid); + if (i != mEIDMap.end()) { + IntDstMap& dst_map = (*i).second; + dst_map.clear(); + } +} + +void +av::NetMap::dump(std::ostream& os) const +{ + if (!mEIDMap.empty()) { + EIDMapMap::const_iterator i; + + os << "NetMap::dump>: " + << mEIDMap.size() + << " entries" + << std::endl; + + for (i=mEIDMap.begin(); i!=mEIDMap.end(); i++) { + const std::string& eid = (*i).first; + os << " eid: " + << eid + << std::endl; + const IntDstMap& dst_map = (*i).second; + IntDstMap::const_iterator j; + for (j=dst_map.begin(); j!=dst_map.end(); j++) { + int num = (*j).first; + os << " " + << num + << std::endl; + } + } + } +} diff --git a/avango-core/src/avango/network/NetNode.cpp b/avango-core/src/avango/network/NetNode.cpp new file mode 100644 index 00000000..beed73c9 --- /dev/null +++ b/avango-core/src/avango/network/NetNode.cpp @@ -0,0 +1,1256 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/NetNode.h" + +#include +#include // std::ostringstream +#include + +#include +#include +#include +#include + +#include "Helper.h" +#include "NetGroup.h" + +#include + +#if defined(ZMQ_DISTRIBUTION_SUPPORT) +#include "NetNodeClient.h" +#include "NetNodeServer.h" +#include +#endif + +namespace +{ + av::Logger &logger(av::getLogger("av::NetNode")); + +#if defined(ZMQ_DISTRIBUTION_SUPPORT) + av::NetNodeClient* gClient = 0; + av::NetNodeServer* gServer = 0; + const std::string gClientEndpoint("{Endpt:127.0.0.2:34818:215:0}"); + const std::string gServerEndpoint("{Endpt:127.0.0.2:34818:215:0}"); +#endif +} + +/* static */ const unsigned int av::NetNode::sCreateMsg = 42; +/* static */ const unsigned int av::NetNode::sUpdateMsg = 43; +/* static */ const unsigned int av::NetNode::sDeleteMsg = 44; +/* static */ const unsigned int av::NetNode::sPackedMsg = 50; +/* static */ const unsigned int av::NetNode::sStateTransferMsg = 45; + +av::NetNode::NetNode() + : mMember(0), + mNumMembers(0), + mWellKnownObjects(), + mBlocked(false) +{} + +av::NetNode::~NetNode() +{ + leave(); +} + +void +av::NetNode::join(const std::string& groupName) +{ +#ifdef AVANGO_DEBUG + logger.debug() << "av::NetNode::NetNode: joining group: " << groupName; +#endif + +#ifdef ZMQ_DISTRIBUTION_SUPPORT + bool isServer; + std::string hostName; + std::string port; + uint64_t serverHWM = 2; + { + // from http://stackoverflow.com/questions/541561/using-boost-tokenizer-escaped-list-separator-with-different-parameters + std::string gn(groupName); + + typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; + boost::escaped_list_separator Separator( ' ', '|' ); + Tokenizer tok( gn, Separator ); + unsigned numTokens = 0; + for (Tokenizer::iterator iter = tok.begin(); iter != tok.end(); ++iter) { + ++numTokens; + } + if (3 == numTokens) { + Tokenizer::iterator iter = tok.begin(); + isServer = ("AVSERVER" == *iter); + ++iter; + hostName = *iter; + ++iter; + port = *iter; + } else if (4 == numTokens) { + Tokenizer::iterator iter = tok.begin(); + isServer = ("AVSERVER" == *iter); + ++iter; + hostName = *iter; + ++iter; + port = *iter; + serverHWM = atoi((*iter).c_str()); + } else { + std::stringstream msg; + msg << "ERROR in av::NetNode::join(const std::string& groupName), could not join - invalid CONFIG"; + throw (std::runtime_error(msg.str())); + } + + } + + if (isServer) { + gServer = new NetNodeServer(hostName,port, this, gClientEndpoint, gServerEndpoint, serverHWM); + joined(gServerEndpoint); + + av::Msg av_msg; + getStateFragment(gServerEndpoint,av_msg); + setStateFragment(gClientEndpoint,av_msg); + } else { + gClient = new NetNodeClient(hostName,port, this, gClientEndpoint, gServerEndpoint); + joined(gClientEndpoint); + gClient->start(); + } + //handleNetworkSends(); + //handleNetworkReceives(); + + mIdCounter = 0; + +#else + leave(); + + Maestro_CSX_Options ops; + + // heartbeat is once per second + ops.heartbeatRate = 1000; + ops.groupName = (char*) groupName.c_str(); + ops.transports = "DEERING"; + ops.properties = "Gmp:Sync:Heal:Switch:Frag:Suspect:Flow:Total"; + ops.params = "suspect_max_idle=3:int;suspect_sweep=1.000:time"; + ops.mbrshipType = MAESTRO_SERVER; + ops.xferType = MAESTRO_ATOMIC_XFER; + + // get the command-line options from the database + ops.argv = getEnsOptionsArgv(); + + // check for usage of a groupd and set the corresponding maestro flag + std::string dummy_value; + if (getEnsOption("-groupd", dummy_value)) + ops.groupdFlag = true; + + if (getEnsOption("-properties", dummy_value)) + ops.properties = const_cast (dummy_value.c_str()); + + if (getEnsOption("-verbose", dummy_value)) { + if (getEnsOption("-modes", dummy_value)) + std::cout << " modes : " << dummy_value << std::endl; + if (getEnsOption("-deering_port", dummy_value)) + std::cout << " deering_port: " << dummy_value << std::endl; + if (getEnsOption("-gossip_port", dummy_value)) + std::cout << " gossip_port : " << dummy_value << std::endl; + if (getEnsOption("-gossip_hosts", dummy_value)) + std::cout << " gossip_hosts: " << dummy_value << std::endl; + if (getEnsOption("-properties", dummy_value)) + std::cout << " properties : " << dummy_value << std::endl; + if (getEnsOption("-multiread", dummy_value)) + std::cout << " multiread : " << (dummy_value.empty () ? "on" : dummy_value) << std::endl; + } + + mMember = new NetGroup(this, ops); + mMember->join(); + mEID = mMember->eid().getHotEndpt().name; + joined(mEID); + + handleNetworkSends(); + handleNetworkReceives(); + +#ifdef AVANGO_DEBUG + logger.debug() << "av::NetNode::NetNode: " + << "joined group '" + << groupName.c_str() + << "', my eid: " + << netEID(); +#endif + + mIdCounter = 0; + +#ifdef AVANGO_DEBUG + logger.debug() << "av::NetNode::join: was called from: " << " pid: " << getpid(); + logger.debug() << "av::NetNode::join: completed."; +#endif + +#endif // #ifdef ZMQ_DISTRIBUTION_SUPPORT +} + +void +av::NetNode::leave() +{ + if (mMember) { +#ifdef AVANGO_DEBUG + logger.debug() << "av::NetNode::leave: "; +#endif + // destroy or donate all objects created by ourselves + delete mMember; // leave group + mMember = 0; + } +} + +av::NetID +av::NetNode::generateUniqueId() +{ + assert(onAir()); +#ifdef ZMQ_DISTRIBUTION_SUPPORT + if(gServer) + return NetID(gServerEndpoint, ++mIdCounter); + else + return NetID(gClientEndpoint, ++mIdCounter); +#else + return NetID(netEID(), ++mIdCounter); +#endif + assert(mIdCounter > 0); // detect overflow +} + +bool +av::NetNode::onAir() const +{ +#ifdef ZMQ_DISTRIBUTION_SUPPORT + return true; +#else + return (mMember != 0); +#endif +} + +const std::string& +av::NetNode::netEID() const +{ + return mEID; +} + +// handle network callbacks. +// this gives the network process time to things +void +av::NetNode::handleNetworkSends() +{ + // consume_received_messages(); +#ifdef ZMQ_DISTRIBUTION_SUPPORT + if (0 != gServer) { + notifyGroup(); + } +#else + if (!mBlocked) + notifyGroup(); +#endif +} + +void +av::NetNode::handleNetworkReceives() +{ +#ifdef ZMQ_DISTRIBUTION_SUPPORT + if (gClient) { + consumeReceivedMessages(); + } +#else + while (mMember && mMember->upcallSerializer().handleNextUpcall(this)) + ; +#endif +} + +void +av::NetNode::queueStateFragment(const std::string& fragment, av::Msg& stateMsg) +{ + mStateUpdates.push_back(std::pair(fragment, stateMsg)); +} + +void +av::NetNode::queueRemoveFragment(const std::string& fragment) +{ + mStateRemoves.push_back(fragment); +} + +void +av::NetNode::applyStateFragments() +{ +#ifdef AVANGO_DEBUG + logger.debug() << "av::NetNode::applyStateFragments:" ; +#endif + { + StateUpdateList::iterator current(mStateUpdates.begin()); + + while (current != mStateUpdates.end()) { + setStateFragment((*current).first, (*current).second); + ++current; + } + + mStateUpdates.clear(); + } + + { + StateRemoveList::iterator current(mStateRemoves.begin()); + + while (current != mStateRemoves.end()) { + removeStateFragment(*current); + + ++current; + } + + mStateRemoves.clear(); + } + +} + +// registration of well known nodes. only when registered, well-known nodes can +// receive and send update messages. because they are well known, creation and +// destruction is not announced via the net. +void +av::NetNode::registerWellKnown(const Link& obj, const NetID& id) +{ +#ifdef AVANGO_DEBUG + //LOG_TRACE(logger) << "av::NetNode::register_well_known: " + logger.debug()<< "av::NetNode::register_well_known: " + << "well-known id: " + << id; +#endif + + // make sure we have already joined a group + AV_ASSERT(onAir()); + + if (!obj->isDistributed()) { + // just check wether this is valid well known id + AV_ASSERT(id.isWellKnown()); + + // make also sure this is unique + if (mWellKnownObjects.find(id) != mWellKnownObjects.end()) { + logger.info() << "register_well_known: " + << "<%s> of type <%s> already known!", + getName(obj), obj->getTypeId().getName().c_str(); + + return; + } + + // add to the map + mWellKnownObjects[id] = obj; + + // setup the distribution info structure + obj->setNetInfo(new NetInfo (id, this)); + } else + logger.info() << "register_well_known: " + << "<%s> of type <%s> already distributed!", + getName(obj), obj->getTypeId().getName().c_str(); +} + +void +av::NetNode::unregisterWellKnown(const Link& obj) +{ + // make sure we have already joined a group + AV_ASSERT(onAir()); + + if (obj->isDistributed()) { +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::unregister_well_known: " + << "well-known id: " + << obj->netID(); +#endif + + // make sure the obj is really registered + NetIDDstMap::iterator i = mWellKnownObjects.find(obj->netID()); + AV_ASSERT(i != mWellKnownObjects.end()); + + // remove the network info structure + delete obj->getNetInfo(); + obj->setNetInfo(0); + + // remove object from the map + mWellKnownObjects.erase(i); + } else + logger.info() << "unregister_well_known: " + << "<%s> of type <%s> not yet distributed!", + getName(obj), obj->getTypeId().getName().c_str(); +} + +// registration of distributables. an object can only be distributed in one +// group at a time. all other group members will be able to see and modify a registered +// object. an unregistered object is only visible to the creator. +void +av::NetNode::registerObj(const Link& obj) +{ + registerObj(obj, generateUniqueId()); +} + +// if an object is created by someone else we use this version +void +av::NetNode::registerObj(const Link& obj, const NetID& id) +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::register_obj: " + << "id: " + << id; +#endif + + // make sure we have already joined a group + AV_ASSERT(onAir()); + + // make sure this object is not already distributed + if (!obj->isDistributed()) { + AV_ASSERT(!id.isNull()); + AV_ASSERT(!id.isWellKnown()); + + // take the supplied id and + // setup the distribution info structure + obj->setNetInfo(new NetInfo (id, this)); + + // add to the map + mObjectMap.registerObj(obj); + + // notify the object + obj->becomingDistributed(); + } else + logger.info() << "register_obj: " + << "<%s> of type <%s> already distributed!", + getName(obj), obj->getTypeId().getName().c_str(); +} + +void +av::NetNode::unregisterObj(const Link& obj) +{ + // make sure we have already joined a group + AV_ASSERT(onAir()); + + // make sure this object is distributed + if (obj->isDistributed()) { + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::unregister_obj: " + << "id: " + << obj->netID(); +#endif + + // first remove object from the map ... + mObjectMap.unregisterObj(obj); + + // notify the object + obj->becomingUndistributed(); + } else + logger.info() << "unregister_obj: " + << "<%s> of type <%s> not yet distributed!", + getName(obj), obj->getTypeId().getName().c_str(); +} + +void +av::NetNode::notifyGroup() +{ + // send all changes since the last send + // order is, in fact, important; use only from within + notifyCreations(); + notifyUpdates(); + notifyDeletes(); +} + +// announce a newly distributed object +void +av::NetNode::notifyCreations() +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::notify_creations: " + << "creations pending: " + << mPendingCreations.size(); +#endif + + if (!mPendingCreations.size()) { + return; + } + + typedef std::vector av_dst_vector; + + av_dst_vector tmp(mPendingCreations.begin(), mPendingCreations.end()); + + // erase the pending objects + mPendingCreations.clear(); + + Msg p_msg; + p_msg.setNetNode(this); + + int msg_count(0); + + av_dst_vector::reverse_iterator i; + + // follow it by an absolute update message to fill in the fields + // because the creations go first, there is no possibility of dangling + // references between newly created objects + for (i=tmp.rbegin(); i!=tmp.rend(); ++i) { + p_msg.setType(Msg::absolute); + makeUpdateMessage(p_msg, *i); + ++msg_count; + } + + // send all of the creation messages to the rest of the group + for (i=tmp.rbegin(); i!=tmp.rend(); ++i) { + p_msg.setType(Msg::relative); + makeCreateMessage(p_msg, *i); + ++msg_count; + } + + av_pushMsg(p_msg, msg_count); + // p_msg << packed_msg; + av_pushMsg(p_msg, sPackedMsg); + +#ifdef ZMQ_DISTRIBUTION_SUPPORT + gServer->cast(p_msg); +#else + mMember->cast(p_msg); +#endif +} + +// announce changes to registered distributed objects +void +av::NetNode::notifyUpdates() +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::notify_updates: " + << "updates pending: " + << mPendingUpdates.size(); +#endif + + if (!mPendingUpdates.size()) + return; + + typedef std::vector av_dst_vector; + + av_dst_vector tmp(mPendingUpdates.begin(), mPendingUpdates.end()); + + // erase the pending objects + mPendingUpdates.clear(); + + Msg p_msg; + p_msg.setNetNode(this); + + int msg_count(0); + + av_dst_vector::reverse_iterator i; + + for (i=tmp.rbegin(); i!=tmp.rend(); ++i) { + p_msg.setType(Msg::relative); + makeUpdateMessage(p_msg, *i); + ++msg_count; + } + + av_pushMsg(p_msg,msg_count); + av_pushMsg(p_msg, sPackedMsg); + +#ifdef ZMQ_DISTRIBUTION_SUPPORT + gServer->cast(p_msg); +#else + mMember->cast(p_msg); +#endif +} + +// announce deletion of a distributed object +void +av::NetNode::notifyDeletes() +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::notify_deletes: " + << "deletes pending: " + << mPendingDeletes.size(); +#endif + + if (!mPendingDeletes.size()) + return; + + typedef std::vector av_dst_vector; + + av_dst_vector tmp(mPendingDeletes.begin(), mPendingDeletes.end()); + + // erase the pending objects + mPendingDeletes.clear(); + + Msg p_msg; + p_msg.setNetNode(this); + + int msg_count(0); + + av_dst_vector::reverse_iterator i; + + for (i=tmp.rbegin(); i!=tmp.rend(); ++i) { + makeDeleteMessage(p_msg, *i); + ++msg_count; + } + + av_pushMsg(p_msg,msg_count); + av_pushMsg(p_msg, sPackedMsg); + +#ifdef ZMQ_DISTRIBUTION_SUPPORT + gServer->cast(p_msg); +#else + mMember->cast(p_msg); +#endif +} + +// look for a distributed node which matches the specified id +// this is meant to be used to resolve object ids which come in over the net +// you must be sure that the object exists and is properly registered +bool +av::NetNode::lookup(const NetID& id, Link& result) +{ + // distinguish between well-known and normal objects + if (id.isWellKnown()) { + +#ifdef AVANGO_DEBUG + { + logger.debug()<< "av::NetNode::lookup: " + << "searching w/in " + << mWellKnownObjects.size() + << " well-known objects"; + + NetIDDstMap::iterator i = mWellKnownObjects.begin(); + + while (i != mWellKnownObjects.end()) { + logger.debug()<< "av::NetNode::lookup: " + << (*i).first + << ":" + << (*i).second->netID(); + ++i; + } + } +#endif + + NetIDDstMap::iterator i = mWellKnownObjects.find(id); + + if (i == mWellKnownObjects.end()) { +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::lookup: " + << "failed for: " + << id; +#endif + return false; + } else { + result = (*i).second; +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::lookup: " + << "succeeded for: " + << id; +#endif + return true; + } + } else { + return mObjectMap.lookup(id, result); + } +} + +void +av::NetNode::joined(const std::string& myeid) +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::joined: " + << "called"; +#endif + // add a slot for ourselfes + mObjectMap.addSlot(myeid); + // tell our clients we joined + _join(myeid); +} + +void +av::NetNode::block() +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::block: " + << "called"; +#endif + mBlocked = true; +} + +void +av::NetNode::unblock() +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::unblock: " + << "called"; +#endif + mBlocked = false; +} + +void +av::NetNode::setStateFragment(const std::string& fragment, av::Msg& stateMsg) +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::set_state_fragment: from " + << fragment << " size: " + << stateMsg.getSize() << " bytes."; +#endif + + // this is for the Maestro_Merge_Simple test + if (mObjectMap.slotExists(fragment)) + { + return; + } + + // we need to reset our old state fragment before we receive the new state fragment + if (mObjectMap.slotExists(fragment)) + { + mObjectMap.emptySlot(fragment); + } else + { + mObjectMap.addSlot(fragment); + } + + // decode the state message + Msg sm(stateMsg); + sm.setNetNode(this); + + // first the creations + int num_objects, i; + + av_popMsg(sm, num_objects); + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::set_state_fragment: create messages: " + << num_objects; +#endif + + for (i=0; i >::const_iterator i; + std::vector > state; + + mObjectMap.lookup(fragment, state); + + // pack into one message + + // let any client add something to the state + _getStateFragment(fragment, state_msg); + + // then updates for the same objects + state_msg.setType(Msg::absolute); + + for (i=state.begin(); i!=state.end(); ++i) + { + makeUpdateMessage(state_msg, *i); + } + + av_pushMsg(state_msg, state.size()); + + // first the create messages + for (i=state.begin(); i!=state.end(); ++i) + { + makeCreateMessage(state_msg, *i); + } + + av_pushMsg(state_msg, state.size()); + + // ultra nasty hack + stateOutMsg = state_msg.clone(); + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::get_state_fragment: for " + << fragment << " size: " + << state_msg.getSize() << " bytes."; + logger.debug()<< "av::NetNode::get_state_fragment: create messages: " << state.size(); + logger.debug()<< "av::NetNode::get_state_fragment: update messages: " << state.size(); +#endif +} + +void +av::NetNode::removeStateFragment(const std::string& fragment) +{ + if (mObjectMap.slotExists(fragment)) + { + mObjectMap.removeSlot(fragment); + } + + // let any client add something to the state + _removeStateFragment(fragment); + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::remove_state_fragment: for " + << fragment; +#endif +} + +void +av::NetNode::receiveMessage(const std::string &origin, av::Msg& msg) +{ + // stack up the received messages in any case + // the message needs to carry a reference to the NetNode + // which received it. + boost::mutex::scoped_lock lock(mMessageMutex); + +#ifdef ZMQ_DISTRIBUTION_SUPPORT + // we need to reset our old state fragment before we receive the new state fragment + if (!mObjectMap.slotExists(origin)) + { + logger.debug() << "ALARM: in av::NetNode::receiveMessage !!!!!!!!!!!!!!!! slot was empty for origin " << origin; + mObjectMap.addSlot(origin); + } +#endif + + Msg av_msg(msg); + av_msg.setNetNode(this); + + mReceivedMessages.push_back(av_msg); +} + +void +av::NetNode::consumeReceivedMessages() +{ +#if AVANGO_DEBUG + logger.debug() << "av::NetNode::consume_received_messages: " + << mReceivedMessages.size() << " messages"; +#endif + + // now, just consume all the received messages + boost::mutex::scoped_lock lock(mMessageMutex); + + while (mReceivedMessages.size()) { + consumeMessage(mReceivedMessages.front()); + mReceivedMessages.pop_front(); + } +} + +void +av::NetNode::exitCompleted() +{ +#if AVANGO_DEBUG + logger.debug() << "av::NetNode::exit_completed: "; +#endif +} + +void +av::NetNode::acceptNewView(const std::vector& members, + const std::vector& newMembers, + const std::vector& departedMembers, + av::Msg& msg) +{ + // set our own eid + mNumMembers = members.size(); + + + // notify derived classes + _acceptNewView(members, newMembers, departedMembers); +} + +// make an existing object distributed, make it local again, update it's state +void +av::NetNode::distributeObject(av::Link obj) +{ +#if AVANGO_DEBUG + logger.debug()<< "av::NetNode::distribute_object: '" + << getName (obj) + << "' w/ type id " + << obj->getTypeId().getName().c_str(); +#endif + + if (!obj->getTypeId().isDistributable()) { + logger.info() << "distribute_object: " + << "<%s> of type <%s> not distributable!", + getName(obj), obj->getTypeId().getName().c_str(); + + return; + } + + registerObj(obj); + mPendingCreations.insert(obj); +} + +void +av::NetNode::undistributeObject(av::Link obj) +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::undistribute_object: '" + << getName (obj) + << "' w/ type id " + << obj->getTypeId().getName().c_str(); +#endif + + if (!obj->getTypeId().isDistributable()) { + logger.info() << "undistribute_object: " + << "<%s> of type <%s> not distributable!", + getName(obj), obj->getTypeId().getName().c_str(); + + return; + } + + unregisterObj(obj); + mPendingDeletes.insert(obj); +} + +// make an existing object distributed, make it local again, update it's state +void +av::NetNode::distributeFieldContainer(av::Link obj) +{ + distributeObject(Link(obj)); +} + +void +av::NetNode::undistributeFieldContainer(av::Link obj) +{ + undistributeObject(Link(obj)); +} + + +void +av::NetNode::updateDistributedObject(const av::Link& obj) +{ + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::update_distributed_object: '" + << getName (obj) + << "' w/ type id " + << obj->getTypeId().getName().c_str(); +#endif + + Link dummy; + + // assert(lookup(obj->netID(), dummy)); + + if (lookup(obj->netID(), dummy)) { + mPendingUpdates.insert(obj); + } else { + logger.info() << "update_distributed_object: " + << "<%s> of type <%s> non-existent!", + getName(obj), obj->getTypeId().getName().c_str(); + + undistributeObject(obj); + } +} + +// create messages for any occassion +void +av::NetNode::makeCreateMessage(av::Msg& msg, const av::Link& obj) +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::make_create_message: start: '" + << obj->getTypeId().getName().c_str() + << "' w/ id: " + << obj->netID(); +#endif + + av_pushMsg(msg, obj->netID()); // push object id + av_pushMsg(msg, obj->getTypeId()); // push object type id + av_pushMsg(msg, sCreateMsg); // push message token + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::make_create_message: done: '" + << obj->getTypeId().getName().c_str() + << "' w/ id: " + << obj->netID(); +#endif +} + +void +av::NetNode::makeUpdateMessage(av::Msg& msg, const av::Link& obj) +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::make_update_message: start: '" + << obj->getTypeId().getName().c_str() + << "' w/ id: " + << obj->netID(); +#endif + + av_pushMsg(msg, obj.getPtr()); // push only changes since last time + av_pushMsg(msg, obj->netID()); // push object id + av_pushMsg(msg, obj->getTypeId()); // push object type id + av_pushMsg(msg, sUpdateMsg); // push message token + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::make_update_message: done: '" + << obj->getTypeId().getName().c_str() + << "' w/ id: " + << obj->netID(); +#endif +} + +void +av::NetNode::makeDeleteMessage(av::Msg& msg, const av::Link& obj) +{ +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::make_delete_message: start: '" + << obj->getTypeId().getName().c_str() + << "' w/ id: " + << obj->netID(); +#endif + + av_pushMsg(msg, obj->netID()); + av_pushMsg(msg, sDeleteMsg); + + { + // remove the network info structure after message has been sent + + delete obj->getNetInfo(); + obj->setNetInfo(0); + } + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::make_delete_message: done: '" + << obj->getTypeId().getName().c_str() + << "' (netID deleted)"; +#endif +} + +// take them from the net and do the right thing +void +av::NetNode::consumeMessage(av::Msg& msg) +{ + // pop the message token + + int msg_type; + av_popMsg(msg, msg_type); + + // dispatch the message + switch (msg_type) { + case sCreateMsg: consumeCreateMessage(msg); break; + case sUpdateMsg: consumeUpdateMessage(msg); break; + case sDeleteMsg: consumeDeleteMessage(msg); break; + case sPackedMsg: consumePackedMessage(msg); break; + + default: + std::cout << "av::NetNode::consume_message: " + << "got unknown msg type of '" << msg_type << "'" << std::endl; + // assert(0); + break; + } +} + +void +av::NetNode::consumeCreateMessage(av::Msg& msg) +{ + Type obj_type; + NetID obj_id; + + // check the type ... + av_popMsg(msg, obj_type); + + if (!obj_type.isOfType(Distributed::getClassTypeId())) + { + std::cout << "av::NetNode::consume_create_message: bad (" + << obj_type.getName().c_str() << ")" + << std::endl; + } + + AV_ASSERT(obj_type.isOfType(Distributed::getClassTypeId())); + + // ... and the id + av_popMsg(msg, obj_id); + AV_ASSERT(!obj_id.isWellKnown()); + + Link test_obj; + + if (lookup(obj_id, test_obj)) + { + return; + } + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::consume_create_message: creating a '" + << obj_type.getName().c_str() << "'"; +#endif + + // create a new object of this type and register with the supplied id + Link obj((Distributed*) obj_type.createInstance()); + +#if AVANGO_DEBUG + logger.debug()<< "av::NetNode::consume_create_message: " + << "about to register object "; +#endif + + registerObj(obj, obj_id); + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::consume_create_message: '" + << obj_type.getName().c_str() + << "' w/ id: " + << obj_id; +#endif +} + +void +av::NetNode::consumeUpdateMessage(av::Msg& msg) +{ + Type obj_type; + NetID obj_id; + + // check the type; + av_popMsg(msg, obj_type); + AV_ASSERT(obj_type.isOfType(Distributed::getClassTypeId())); + + // and the id + av_popMsg(msg, obj_id); + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::consume_update_message: '" + << obj_type.getName().c_str() + << "' w/ id: " + << obj_id; +#endif + + Link obj; + + if (!lookup(obj_id, obj)) { + obj = (Distributed*) obj_type.createInstance(); + + std::cerr << "av::NetNode::consume_update_message: created dummy instance of type '" + << obj_type.getName().c_str() + << "' w/ id: " + << obj_id + << " for non-existent object" + << std::endl; + } + + if (obj->getTypeId() == obj_type) { + // fill in the object + av_popMsg(msg, obj.getPtr()); + } +} + +void +av::NetNode::consumeDeleteMessage(av::Msg& msg) +{ + NetID obj_id; + + // check the id + av_popMsg(msg, obj_id); + + // look it up + Link obj; + const bool found = lookup(obj_id, obj); + + if (!found) { + logger.warn() << "av::NetNode::consume_delete_message: " + << "object not found: " + << obj_id; + return; + } + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::consume_delete_message: " + << obj_id; +#endif + + unregisterObj(obj); +} + +void +av::NetNode::consumePackedMessage(av::Msg& msg) +{ + int msg_count; + av_popMsg(msg, msg_count); + +#ifdef AVANGO_DEBUG + logger.debug()<< "av::NetNode::consume_packed_message: " << msg_count; +#endif + + for (int i = 0; i < msg_count; ++i) { + consumeMessage(msg); + } +} + +// ensemble command line option interface +/* static */ std::map > av::NetNode::sEnsOptions; +/* static */ char** av::NetNode::sEnsOptionsArgv = 0; + +/* static */ void +av::NetNode::setEnsOption(const std::string& option, const std::string& value) +{ + sEnsOptions[option] = value; +} + +/* static */ bool +av::NetNode::getEnsOption(const std::string& option, std::string& value) +{ + std::map >::const_iterator i = sEnsOptions.find(option); + + if (i == sEnsOptions.end()) { + return false; + } else { + value = (*i).second; + return true; + } +} + +// for performance reasons, the value returned here is meant to be +// copied and then be forgotten. +/* static */ char** +av::NetNode::getEnsOptionsArgv() +{ + // delete the old argv if present + if (sEnsOptionsArgv) + ::delete [] sEnsOptionsArgv; + + // allocate space for a new one + sEnsOptionsArgv = ::new char* [sEnsOptions.size() * 2 + 3]; + + // assign references to the contents of the map + std::map >::const_iterator i; + char** arg = sEnsOptionsArgv; + + // the program name goes first + *arg++ = "avango"; + + // print ensemble version/copyright stmt + //*arg++ = "-v"; + + for (i = sEnsOptions.begin(); i != sEnsOptions.end(); ++i) { + *arg++ = const_cast((*i).first.c_str()); + if ((*i).second.size()) + *arg++ = const_cast((*i).second.c_str()); + } + // mark the end + *arg = 0; + + return sEnsOptionsArgv; +} diff --git a/avango-core/src/avango/network/NetNodeClient.cpp b/avango-core/src/avango/network/NetNodeClient.cpp new file mode 100644 index 00000000..ee1b0853 --- /dev/null +++ b/avango-core/src/avango/network/NetNodeClient.cpp @@ -0,0 +1,102 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "NetNodeClient.h" + +#include +#include + +#include +#include + +av::NetNodeClient::NetNodeClient(const std::string& host, const std::string& port, av::NetNode* netnode, const std::string& ce, const std::string& se) + : mHost(host), + mPort(port), + mThread(0), + mRunning(false), + mNetNode(netnode), + mClientEndpoint(ce), + mServerEndpoint(se) +{} + +av::NetNodeClient::~NetNodeClient() +{ + stop(); + // wait + + if (mThread) + delete mThread; +} + +void +av::NetNodeClient::start() +{ + // launch thread: + av::Msg dummy_msg; + mNetNode->getStateFragment(mClientEndpoint, dummy_msg); + mNetNode->setStateFragment(mServerEndpoint, dummy_msg); + + if(!mRunning && !mThread) + { + mRunning = true; + mThread = new boost::thread(boost::bind(&NetNodeClient::loop, this)); + } + else + { + std::cerr << "ALARM in NetNodeClient::start() , thread already running!" << std::endl; + } +} + +void +av::NetNodeClient::stop() +{ + mRunning = false; +} + +void +av::NetNodeClient::loop() +{ + // open connection + zmq::context_t ctx(1); // means single threaded + zmq::socket_t socket(ctx, ZMQ_SUB); // means a subscriber + + socket.setsockopt(ZMQ_SUBSCRIBE, "", 0); + + std::string endpoint("tcp://" + mHost + ":" + mPort); + socket.connect(endpoint.c_str()); + + zmq::message_t zmq_message; + + while (mRunning) + { + socket.recv(&zmq_message); // blocking + + av::Msg av_msg; + av_msg.resize(zmq_message.size()); + memcpy(av_msg.getBuffer(), zmq_message.data(), zmq_message.size()); + + mNetNode->receiveMessage(mServerEndpoint, av_msg); + } +} diff --git a/avango-core/src/avango/network/NetNodeClient.h b/avango-core/src/avango/network/NetNodeClient.h new file mode 100644 index 00000000..8b370d70 --- /dev/null +++ b/avango-core/src/avango/network/NetNodeClient.h @@ -0,0 +1,72 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + + +#if !defined(AVANGO_NETNODECLIENT_H) +#define AVANGO_NETNODECLIENT_H + +#include + +namespace boost +{ + class thread; +} + +namespace av +{ + class NetNode; + + class NetNodeClient + { + + public: + + NetNodeClient(const std::string& host, const std::string& port, av::NetNode* netnode, const std::string& ce, const std::string& se); + + ~NetNodeClient(); + + // called from NetNode + void start(); + + void stop(); + + private: + + // the thread loop + void loop(); + + std::string mHost; + std::string mPort; + boost::thread* mThread; + bool mRunning; + av::NetNode* mNetNode; + std::string mClientEndpoint; + std::string mServerEndpoint; + + }; + +} // namespace av + +#endif // #ifndef AVANGO_NETNODECLIENT_H diff --git a/avango-core/src/avango/network/NetNodeServer.cpp b/avango-core/src/avango/network/NetNodeServer.cpp new file mode 100644 index 00000000..59fbb9ee --- /dev/null +++ b/avango-core/src/avango/network/NetNodeServer.cpp @@ -0,0 +1,56 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "NetNodeServer.h" + +#include + +av::NetNodeServer::NetNodeServer(const std::string& host, const std::string& port, av::NetNode* netnode, const std::string& ce, const std::string& se, uint64_t hwm) + : mHost(host), + mPort(port), + mNetNode(netnode), + mCtx(1), + mSocket(mCtx, ZMQ_PUB), + mClientEndpoint(ce), + mServerEndpoint(se) +{ + //int64_t rate(500); + //mSocket.setsockopt(ZMQ_RATE,&rate, sizeof(rate)); + + mSocket.setsockopt(ZMQ_HWM,&hwm, sizeof(hwm)); + std::string endpoint("tcp://" + mHost + ":" + mPort); + mSocket.bind(endpoint.c_str()); +} + +av::NetNodeServer::~NetNodeServer() +{} + +void +av::NetNodeServer::cast(av::Msg& av_msg) +{ + zmq::message_t zmq_message(av_msg.getSize()); + memcpy(zmq_message.data(), av_msg.getBuffer(), av_msg.getSize()); + mSocket.send(zmq_message); +} diff --git a/avango-core/src/avango/network/NetNodeServer.h b/avango-core/src/avango/network/NetNodeServer.h new file mode 100644 index 00000000..d352e657 --- /dev/null +++ b/avango-core/src/avango/network/NetNodeServer.h @@ -0,0 +1,61 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_NETNODESERVER_H) +#define AVANGO_NETNODESERVER_H + +#include +#include + +#include + +namespace av +{ + class NetNode; + + class NetNodeServer + { + + public: + NetNodeServer(const std::string& host, const std::string& port, av::NetNode* netnode, const std::string& ce, const std::string& se, uint64_t hwm); + ~NetNodeServer(); + + // called from NetNode + void cast(av::Msg& av_msg); + + private: + + std::string mHost; + std::string mPort; + av::NetNode* mNetNode; + zmq::context_t mCtx; + zmq::socket_t mSocket; + std::string mClientEndpoint; + std::string mServerEndpoint; + }; + +}; + +#endif // #ifndef AVANGO_NETNODESERVER_H diff --git a/avango-core/src/avango/network/UpcallSerializer.cpp b/avango-core/src/avango/network/UpcallSerializer.cpp new file mode 100644 index 00000000..0cb6746d --- /dev/null +++ b/avango-core/src/avango/network/UpcallSerializer.cpp @@ -0,0 +1,320 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "UpcallSerializer.h" + +#include +#include +#include + +#define AVANGO_UPCALLSERIALIZER_DEBUG 4 +#undef AVANGO_UPCALLSERIALIZER_DEBUG + +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) +# include +# include +#endif + +av::Upcall::Upcall() +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "Upcall::Upcall(): @0x" << static_cast (this) << " ..." << std::endl; +#endif +} + +av::Upcall::~Upcall() +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "Upcall::~Upcall(): @0x" << static_cast (this) << " ..." << std::endl; +#endif +} + +// called from net process +void +av::JoinUpcall::upcallQueued(UpcallSerializer&) +{} + +// called from app process +void +av::JoinUpcall::handle(NetNode* netNode, UpcallSerializer&) +{ + netNode->joined(mEID); + +} + +// called from net process +void +av::SetStateUpcall::upcallQueued(UpcallSerializer&) +{} + +// called from app process +void +av::SetStateUpcall::handle(NetNode* netNode, UpcallSerializer&) +{ + netNode->setStateFragment(mFragment, mStateMsg); + +} + +// called from net process +void +av::GetStateUpcall::upcallQueued(UpcallSerializer& serializer) +{ + serializer.netWait(); +} + +// called from app process +void +av::GetStateUpcall::handle(NetNode* netNode, UpcallSerializer& serializer) +{ + netNode->getStateFragment(mFragment, mStateMsg); + serializer.signalWait(); +} + +// called from net process +void +av::RemoveStateUpcall::upcallQueued(UpcallSerializer&) +{} + +// called from app process +void +av::RemoveStateUpcall::handle(NetNode* netNode, UpcallSerializer&) +{ + netNode->removeStateFragment(mFragment); + +} + +// called from net process +void +av::MessageUpcall::upcallQueued(UpcallSerializer&) +{} + +// called from app process +void +av::MessageUpcall::handle(NetNode* netNode, UpcallSerializer&) +{ + Msg sm(mMsg); + sm.setNetNode(netNode); + netNode->consumeMessage(sm); + +} + +// called from net process +void +av::AcceptedViewUpcall::upcallQueued(UpcallSerializer&) +{} + +// called from app process +void +av::AcceptedViewUpcall::handle(NetNode* netNode, UpcallSerializer&) +{ + netNode->acceptNewView(mMembers, mNewMembers, mDepartedMembers, mMsg); + +} + +// called from net process +void +av::BlockUpcall::upcallQueued(UpcallSerializer& serializer) +{ + serializer.netWait(); +} + +// called from app process +void +av::BlockUpcall::handle(NetNode* netNode, UpcallSerializer& serializer) +{ + netNode->block(); + serializer.signalWait(); +} + +// called from net process +void +av::UnblockUpcall::upcallQueued(UpcallSerializer& /* serializer */) +{ + // serializer.net_wait(); +} + +// called from app process +void +av::UnblockUpcall::handle(NetNode* netNode, UpcallSerializer& /* serializer */) +{ + netNode->unblock(); + // serializer.signal_wait(); +} + +// called from net process +void +av::ExitUpcall::upcallQueued(UpcallSerializer& serializer) +{ + serializer.netWait(); +} + +// called from app process +void +av::ExitUpcall::handle(NetNode* netNode, UpcallSerializer& serializer) +{ + netNode->exitCompleted(); + serializer.signalWait(); +} + +av::UpcallSerializer::UpcallSerializer() + : mUpcallQueueLock(), + mUpcallQueue(), + mSyncSema(0) +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::UpcallSerializer(): " + << "w/ sema @" << &mSyncSema << " (val: " << mSyncSema.snapshot() << ") ..." + << std::endl; +#endif +} + +av::UpcallSerializer::~UpcallSerializer() +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::~UpcallSerializer(): " + << "w/ sema @" << &mSyncSema << " (val: " << mSyncSema.snapshot() << ") ..." + << std::endl; +#endif +} + +#if defined(BOOST_SP_DISABLE_THREADS) +#define BOOST_SHAREDPTR_THREAD_SUPPORT_ENABLED false +#else +#define BOOST_SHAREDPTR_THREAD_SUPPORT_ENABLED true +#endif + +#define BOOST_IS_RIGHT_VERSION (BOOST_VERSION >= 103300) + +// called from net process +void +av::UpcallSerializer::makeUpcall(boost::shared_ptr upcall) +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::make_upcall(): " + << "'" << typeid(upcall).name() << "' @0x" << static_cast (upcall.get()) + << " ..." + << std::endl; +#endif + + BOOST_STATIC_ASSERT(BOOST_IS_RIGHT_VERSION && BOOST_SHAREDPTR_THREAD_SUPPORT_ENABLED); + + { + boost::mutex::scoped_lock lock(mUpcallQueueLock); + + mUpcallQueue.push_back(upcall); + } + + upcall->upcallQueued(*this); +} + +// called from app process +void +av::UpcallSerializer::handleUpcall(boost::shared_ptr upcall, NetNode* netNode) +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::handle_upcall(): " + << "'" << typeid(upcall).name() << "' @0x" << static_cast (upcall.get()) + << " ..." + << std::endl; +#endif + + upcall->handle(netNode, *this); +} + +// called from app process +bool +av::UpcallSerializer::handleNextUpcall(NetNode* netNode) +{ + boost::shared_ptr upcall; + + { + boost::mutex::scoped_lock lock(mUpcallQueueLock); + + if (!mUpcallQueue.empty()) { + upcall = mUpcallQueue.front(); + + mUpcallQueue.pop_front(); + } + } + + if (upcall) { + handleUpcall(upcall, netNode); + + return true; + } + + return false; +} + +void +av::UpcallSerializer::netWait() +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::net_wait(): " + << "waiting on sema @" << &mSyncSema + << " (val: " << mSyncSema.snapshot() << ") ..." + << std::endl; +#endif + + mSyncSema.wait(); + +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::net_wait(): " + << "done waiting on sema @" << &mSyncSema << " ..." + << std::endl; +#endif +} + +void +av::UpcallSerializer::signalWait() +{ +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::signal_wait(): " + << "sleeping while for sema @" << &mSyncSema + << " (val: " << mSyncSema.snapshot() << ") ..." + << std::endl; +#endif + + // wait until a wait has really been performed + while (mSyncSema.snapshot() == 0) { + usleep(1); + } + +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::signal_wait(): " + << "done sleeping on sema @" << &mSyncSema + << " (val: " << mSyncSema.snapshot() << ") ..." + << std::endl; +#endif + + mSyncSema.post(); + +#if defined(AVANGO_UPCALLSERIALIZER_DEBUG) + std::cerr << "UpcallSerializer::signal_wait(): " + << "posted sema @" << &mSyncSema + << " (val: " << mSyncSema.snapshot() << ") ..." + << std::endl; +#endif +} diff --git a/avango-core/src/avango/network/UpcallSerializer.h b/avango-core/src/avango/network/UpcallSerializer.h new file mode 100644 index 00000000..8a8287d5 --- /dev/null +++ b/avango-core/src/avango/network/UpcallSerializer.h @@ -0,0 +1,285 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_UPCALLSERIALIZER_H) +#define AVANGO_UPCALLSERIALIZER_H + +#include +#include +#include +#include + +#include +#include + +// #include "MaestroMerge.h" + +namespace av +{ + + class NetID; + class NetNode; + class UpcallSerializer; + + class Upcall { + + public: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer) = 0; + // called from app process + virtual void handle(NetNode* net_node, UpcallSerializer& serializer) = 0; + + virtual ~Upcall(); + + protected: + + Upcall(); + + + }; + + class JoinUpcall : public Upcall { + + public: + + JoinUpcall(const std::string& eid) + : mEID(eid) {} + ~JoinUpcall() {} + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* net_node, UpcallSerializer& serializer); + + private: + + std::string mEID; + + }; + + class GetStateUpcall : public Upcall { + + public: + + GetStateUpcall(const std::string& fragment) + : mFragment(fragment) {} + ~GetStateUpcall() {} + + Msg stateMsg() + { + return mStateMsg; + } + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* net_node, UpcallSerializer& serializer); + + private: + + std::string mFragment; + Msg mStateMsg; + + }; + + class SetStateUpcall : public Upcall { + + public: + + SetStateUpcall(const std::string& fragment, Msg& stateMsg) + : mFragment(fragment), mStateMsg(stateMsg) {} + ~SetStateUpcall() {} + + const Msg& stateMsg() + { + return mStateMsg; + } + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* netNode, UpcallSerializer& serializer); + + private: + + std::string mFragment; + Msg mStateMsg; + + }; + + class RemoveStateUpcall : public Upcall { + + public: + + RemoveStateUpcall(const std::string& fragment) + : mFragment(fragment) {} + ~RemoveStateUpcall() {} + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* netNode, UpcallSerializer& serializer); + + private: + + std::string mFragment; + + }; + + class MessageUpcall : public Upcall { + + public: + + MessageUpcall(Msg& msg) + : mMsg(msg) {} + ~MessageUpcall() {} + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* netNode, UpcallSerializer& serializer); + + private: + + Msg mMsg; + + }; + + class AcceptedViewUpcall : public Upcall { + + public: + + AcceptedViewUpcall(const std::vector& members, + const std::vector& newMembers, + const std::vector& departedMembers, + Msg &msg) + : mMembers(members), mNewMembers(newMembers), mDepartedMembers(departedMembers), mMsg(msg) {} + ~AcceptedViewUpcall() {} + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* netNode, UpcallSerializer& serializer); + + private: + std::vector mMembers; + std::vector mNewMembers; + std::vector mDepartedMembers; + Msg mMsg; + }; + + class BlockUpcall : public Upcall { + + public: + + BlockUpcall() {} + ~BlockUpcall() {} + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* netNode, UpcallSerializer& serializer); + + }; + + class UnblockUpcall : public Upcall { + + public: + + UnblockUpcall() {} + ~UnblockUpcall() {} + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* netNode, UpcallSerializer& serializer); + + }; + + class ExitUpcall : public Upcall { + + public: + + ExitUpcall() {} + ~ExitUpcall() {} + + protected: + + // called from net process + virtual void upcallQueued(UpcallSerializer& serializer); + // called from app process + virtual void handle(NetNode* netNode, UpcallSerializer& serializer); + + }; + + + class UpcallSerializer { + + public: + + UpcallSerializer(); + ~UpcallSerializer(); + + // called from net process + void makeUpcall(boost::shared_ptr upcall); + // called from app process + bool handleNextUpcall(NetNode* netNode); + + void netWait(); + void signalWait(); + + protected: + + // called from app process + void handleUpcall(boost::shared_ptr upcall, NetNode* netNode); + + private: + + boost::mutex mUpcallQueueLock; + std::deque > mUpcallQueue; + Semaphore mSyncSema; + + }; + +} // namespace av + +#endif // #if !defined(AVANGO_UPCALLSERIALIZER_H) diff --git a/avango-core/src/avango/network/tests/TestNetLock.cpp b/avango-core/src/avango/network/tests/TestNetLock.cpp new file mode 100644 index 00000000..5fd0a725 --- /dev/null +++ b/avango-core/src/avango/network/tests/TestNetLock.cpp @@ -0,0 +1,73 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include + +namespace +{ + class NetLockFixture { + public: + NetLockFixture() { av::NetLock::initClass(); } + }; + + TEST_FIXTURE(NetLockFixture, InitializeNetLock) + { + CHECK(av::Type::getByName("av::NetLock") != av::Type::badType()); + } + + TEST_FIXTURE(NetLockFixture, CheckProtocol) + { + av::Link lock(new av::NetLock); + + // Lock is initially not granted, we are the first one + lock->Request.setValue("Test1"); + av::ApplicationInstance::get().evaluate(); + CHECK_EQUAL(std::string("Test1"), lock->Granted.getValue()); + + // Lock is granted to "Test1", cannot be granted to Test2 + lock->Request.setValue("Test2"); + av::ApplicationInstance::get().evaluate(); + CHECK_EQUAL(std::string("Test1"), lock->Granted.getValue()); + + // Lock can only be released by "Test1" + lock->Release.setValue("Test2"); + av::ApplicationInstance::get().evaluate(); + CHECK_EQUAL(std::string("Test1"), lock->Granted.getValue()); + + lock->Release.setValue("Test1"); + av::ApplicationInstance::get().evaluate(); + CHECK_EQUAL(std::string(""), lock->Granted.getValue()); + + // Now Lock is free and can be requested by "Test2" + + lock->Request.setValue("Test2"); + av::ApplicationInstance::get().evaluate(); + CHECK_EQUAL(std::string("Test2"), lock->Granted.getValue()); + } + + +} diff --git a/avango-core/src/avango/network/tests/TestNetNode.cpp b/avango-core/src/avango/network/tests/TestNetNode.cpp new file mode 100644 index 00000000..68a18201 --- /dev/null +++ b/avango-core/src/avango/network/tests/TestNetNode.cpp @@ -0,0 +1,130 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace +{ + bool value = 0; + + class MyBoolObject : public av::BoolObject + { + AV_FC_DECLARE(); + + public: + + virtual void fieldHasChangedLocalSideEffect(const av::Field&); + + }; + + AV_FC_DEFINE(MyBoolObject); + + void MyBoolObject::fieldHasChangedLocalSideEffect(const av::Field&) + { + value = Value.getValue(); + } + + void MyBoolObject::initClass() + { + if (!isTypeInitialized()) + { + av::BoolObject::initClass(); + AV_FC_INIT(av::BoolObject, MyBoolObject, true); + } + } + + class MyNetNode : public av::NetNode + { + public: + MyNetNode() + { + setEnsOption("-deering_port", "2346"); + setEnsOption("-multiread", ""); + //set_ens_option("-verbose", ""); + //set_ens_option("-socket_verb", ""); + //set_ens_option("-prbool_config", ""); + //set_ens_option("-prbool_defaults", ""); + //set_ens_option("-gc_verb", ""); + //set_ens_option("-trace", "avango"); + //set_ens_option("-traces", "avango"); + } + }; + + TEST(useNetNode) + { + MyBoolObject::initClass(); + std::string net_group_name = "av_net_group"; + + pid_t pid = ::fork(); + + if (0 == pid) // child + { + MyNetNode net_node; + net_node.join(net_group_name); + + av::Link bool_obj(new MyBoolObject); + bool_obj->Value.setValue(true); + net_node.distributeObject(bool_obj.getPtr()); + + while (true) + { + ::usleep(100000); + net_node.handleNetworkReceives(); + net_node.handleNetworkSends(); + } + + ::_exit(0); + } + else // parent + { + MyNetNode net_node; + net_node.join(net_group_name); + + for (int i=0; i<50; ++i) + { + ::usleep(100000); + net_node.handleNetworkReceives(); + net_node.handleNetworkSends(); + if (value) break; + } + + ::kill(pid, SIGTERM); + ::waitpid(pid, 0, 0); + + CHECK(value); + } + } +} // namespace diff --git a/avango-core/src/avango/network/tests/TestNetwork.cpp b/avango-core/src/avango/network/tests/TestNetwork.cpp new file mode 100644 index 00000000..bc8f0e10 --- /dev/null +++ b/avango-core/src/avango/network/tests/TestNetwork.cpp @@ -0,0 +1,41 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +// includes, system + +// includes, project + +#include +#include +#include + +int main() +{ + av::getRootLogger().addConsoleAppender(); + av::ApplicationInstance::get(); + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/nodes/Base.cpp b/avango-core/src/avango/nodes/Base.cpp new file mode 100644 index 00000000..ff5f91b3 --- /dev/null +++ b/avango-core/src/avango/nodes/Base.cpp @@ -0,0 +1,240 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include "avango/Base.h" + +// includes, system + +#include +#include +#include + +// includes, project + +#include +#include + +#include + +// internal unnamed namespace + +namespace +{ + // types, internal + + // variables, internal + + bool delete_on_unref = 1; + + av::Logger& logger(av::getLogger("av::Base")); + + // functions, internal + +} // namespace + +// variables, exported + +// functions, exported + +AV_TYPED_DEFINE_ABSTRACT(av::Base); + +av::Base::Base() + : mRefCount(0), mHasFloatingRef(false) +{ + AVANGO_LOG(logger,logging::TRACE , boost::str(boost::format("Base(): @0x%1%") % this)); +} + +/* virtual */ +av::Base::~Base() +{ + AVANGO_LOG(logger,logging::TRACE , boost::str(boost::format("~Base(): @0x%1%") % this)); +} + +/* static */ void +av::Base::initClass() +{ + if (!isTypeInitialized()) { + av::Typed::initClass(); + + AV_TYPED_INIT_ABSTRACT(av::Typed, av::Base, true); + + delete_on_unref = (0 == ::getenv("AVANGO_NO_DELETE_ON_UNREF")); + + if (!delete_on_unref) + { + AVANGO_LOG(logger,logging::INFO , "initClass: disabling 'delete this' when reference count goes to zero!"); + } + } +} + +av::Base* +av::Base::castTo(Type type) +{ + if (getTypeId().isOfType(type)) + return this; + + return 0; +} + +/* static */ av::Base* +av::Base::castTo(Type type, Base* objectToCast) +{ + if (!objectToCast) { + return 0; + } + return objectToCast->castTo(type); +} + +void +av::Base::reference() +{ + refImpl(); + + AVANGO_LOG(logger,logging::TRACE , boost::str(boost::format("reference(): '%1%' @0x%2% refcount = %3% after ref") % getTypeId().getName().c_str() % this % referenceCount())) + +} + +void +av::Base::unreference() +{ + AVANGO_LOG(logger,logging::TRACE , boost::str(boost::format("reference(): '%1%' @0x%2% refcount = %3% before unref") % getTypeId().getName().c_str() % this % referenceCount())) + + unrefImpl(); +} + +void +av::Base::unreferenceWithoutDeletion() +{ + AVANGO_LOG(logger,logging::TRACE , boost::str(boost::format("reference(): '%1%' @0x%2% refcount = %3% before unref") % getTypeId().getName().c_str() % this % referenceCount())) + + unrefWithoutDeletionImpl(); +} + +int +av::Base::referenceCount() +{ + return refCountImpl(); +} + +void +av::Base::setFloatingReference() +{ + setFloatingRefImpl(); +} + +/* virtual */ void +av::Base::refImpl() +{ + ++mRefCount; + mHasFloatingRef = false; +} + +/* virtual */ void +av::Base::unrefImpl() +{ + assert(mRefCount > 0); + + --mRefCount; + + if (delete_on_unref && !mHasFloatingRef && (mRefCount == 0)) + { + delete this; + } +} + +/* virtual */ void +av::Base::unrefWithoutDeletionImpl() +{ + assert(mRefCount > 0); + + --mRefCount; +} + +/* virtual */ int +av::Base::refCountImpl() +{ + return mRefCount; +} + +/*virtual*/ void +av::Base::setFloatingRefImpl() +{ + mHasFloatingRef = true; +} + +/* virtual */ void +av::Base::doAction(Action&) +{} + +/* virtual */ void +av::Base::doWriteAction(WriteAction& action) +{ + if (action.getStream().isBinaryEnabled()) { + writeToBinaryStream(action); + } else { + writeToASCIIStream(action); + } +} + +void +av::Base::writeToBinaryStream(WriteAction& action) +{ + action.getStream() << getTypeId().getName(); + action.getStream() << action.lookupObjectId(this); + operator<<(action.getStream(), this); +} + +void +av::Base::writeToASCIIStream(WriteAction& action) +{ + (std::ostream&)(action.getStream() << getTypeId().getName()) << " "; + action.getStream() << action.lookupObjectId(this) << std::endl; + operator<<(action.getStream(), this); + action.getStream() << std::endl; +} + +/* virtual */ void +av::Base::read(InputStream&) +{} + +/* virtual */ void +av::Base::write(OutputStream&) +{} + +av::InputStream& +av::operator>>(InputStream& is, Base* obj) +{ + obj->read(is); + return is; +} + +av::OutputStream& +av::operator<<(OutputStream& os, Base* obj) +{ + obj->write(os); + return os; +} diff --git a/avango-core/src/avango/nodes/Distributed.cpp b/avango-core/src/avango/nodes/Distributed.cpp new file mode 100644 index 00000000..5b971713 --- /dev/null +++ b/avango-core/src/avango/nodes/Distributed.cpp @@ -0,0 +1,168 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include "avango/Distributed.h" + +// includes, system + +#include + +// includes, project + +#include + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) +#include +#include +#include +#include +#include +#endif + +#define AVANGO_DISTRIBUTED_DEBUG +#undef AVANGO_DISTRIBUTED_DEBUG + +// internal unnamed namespace + +namespace +{ + // types, internal + + // variables, internal + + av::logging::Logger& logger(av::logging::Logger::getLogger("av::Distributed")); + + // functions, internal + +} // namespace + +// variables, exported + +// functions, exported + +AV_BASE_DEFINE_ABSTRACT(av::Distributed) + +av::Distributed::Distributed() +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + : mNetInfo(0) +#endif +{} + +/* virtual */ +av::Distributed::~Distributed() +{} + +/* static */ void +av::Distributed::initClass() +{ + if (!isTypeInitialized()) + { + Base::initClass(); + + AV_BASE_INIT_ABSTRACT(av::Base, av::Distributed, true); + } +} + +bool +av::Distributed::isOwned() const +{ +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + return (!isDistributed() || (netCreator() == netNode()->netEID())); +#else + return true; +#endif +} + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + +bool +av::Distributed::isDistributed() const +{ + return (mNetInfo != 0); +} + +av::NetInfo* +av::Distributed::getNetInfo() +{ + return mNetInfo; +} + +void +av::Distributed::setNetInfo(NetInfo* netInfo) +{ + mNetInfo = netInfo; +} + +void +av::Distributed::notifyLocalChange() +{ + if (!isDistributed()) + { + return; + } + + Link tmp(this); + mNetInfo->mNode->updateDistributedObject(tmp); +} + +const av::NetID& +av::Distributed::netID() const +{ + AV_ASSERT(mNetInfo); + return mNetInfo->getId(); +} + +const std::string& +av::Distributed::netCreator() const +{ + AV_ASSERT(mNetInfo); + return mNetInfo->getId().getEID(); +} + +const av::NetNode* +av::Distributed::netNode() const +{ + AV_ASSERT(mNetInfo); + return mNetInfo->getNode(); +} + +av::NetNode* +av::Distributed::netNode() +{ + AV_ASSERT(mNetInfo); + return mNetInfo->getNode(); +} + +/* virtual */ void +av::Distributed::becomingDistributed() +{} + +/* virtual */ void +av::Distributed::becomingUndistributed() +{} + +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) diff --git a/avango-core/src/avango/nodes/FieldContainer.cpp b/avango-core/src/avango/nodes/FieldContainer.cpp new file mode 100644 index 00000000..55348a1a --- /dev/null +++ b/avango-core/src/avango/nodes/FieldContainer.cpp @@ -0,0 +1,754 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#include "avango/FieldContainer.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ + av::Logger& logger(av::Logger::getLogger("av::FieldContainer")); + + typedef std::list > FieldContainerList; + + FieldContainerList& evaluation_list = *new FieldContainerList; + + std::string empty_string; +} // namespace + +AV_BASE_DEFINE_ABSTRACT(av::FieldContainer); + +AV_FIELD_DEFINE(av::SFContainer); +AV_FIELD_DEFINE(av::MFContainer); + +unsigned int av::FieldContainer::sEvaluateId = 0u; + +av::FieldContainer::FieldContainer() : + mEvaluateId(0u) +{ + mFlags.mNeedsEvaluation = false; + mFlags.mIsInEvaluationList = false; + mFlags.mFieldsCalculated = false; + mFlags.mAlwaysEvaluate = false; + mFlags.mIsEvaluating = false; + mFlags.mAllowScheduling = true; + + // Register with pool and set ID to the one, generated by the pool + // as response to registration. + mId = av::ContainerPool::registerInstance(this); + av::ContainerPool::notifyCreation(this); + + AV_FC_ADD_ADAPTOR_FIELD(Name, + boost::bind(&av::FieldContainer::getNameCB, this, _1), + boost::bind(&av::FieldContainer::setNameCB, this, _1)); +} + +/* virtual */ +av::FieldContainer::~FieldContainer() +{ + av::ContainerPool::notifyDeletion(this); + av::ContainerPool::unregisterInstance(this); + + // delete owned fields + for (FieldInfos::iterator field = mFields.begin(); field != mFields.end(); ++field) + { + if (field->mField->isOwned()) + delete field->mField; + } +} + +/* static */ void +av::FieldContainer::initClass() +{ + if (!isTypeInitialized()) + { + Distributed::initClass(); + + AV_BASE_INIT_ABSTRACT(av::Distributed, av::FieldContainer, true); + + SFContainer::initClass("av::SFContainer", "av::Field"); + MFContainer::initClass("av::MFContainer", "av::Field"); + } +} + + +unsigned int +av::FieldContainer::addField(Field* field, const std::string& fieldName) +{ + AV_ASSERT(field); + + FieldInfo newFieldInfo; + newFieldInfo.mField = field; + newFieldInfo.mName = fieldName; + + mFields.push_back(newFieldInfo); + mFieldsIndex.insert(std::make_pair(newFieldInfo.mName, mFields.size()-1)); + + mFlags.mFieldsCalculated = false; + + return mFields.size() - 1; +} + +av::FieldContainer::FieldInfo* +av::FieldContainer::getFieldInfo(const std::string& name) +{ + FieldsIndex::iterator iter = mFieldsIndex.find(name); + if(iter == mFieldsIndex.end()) { + return 0; + } else { + return &mFields[iter->second]; + } +} + +av::FieldContainer::FieldInfo* +av::FieldContainer::getFieldInfo(unsigned int index) +{ + return (index < mFields.size() ? &mFields[index] : 0); +} + +unsigned int +av::FieldContainer::getNumFields() +{ + return mFields.size(); +} + +/* virtual */ void +av::FieldContainer::addDynamicField(const std::string& typeName, const std::string& fieldName) +{ + //check if a field with the given name already exists + FieldsIndex::iterator fieldIter = mFieldsIndex.find(fieldName); + AV_ASSERT(fieldIter == mFieldsIndex.end()); + + Typed *typed = av::Type::createInstanceOfType(typeName); + if (typed != 0) + { + Field *field = dynamic_cast(typed); + if (field != 0) + { + field->bind(this, fieldName, true); + } + else + { + delete typed; + AVANGO_LOG(logger,logging::WARN , boost::str(boost::format("type '%1%' is no field") % typeName)) + } + } + else + { + AVANGO_LOG(logger,logging::WARN , boost::str(boost::format("could not create instance of type '%1%'") % typeName)) + } +} + +/* virtual */ void +av::FieldContainer::addDynamicField(Field* field, const std::string& fieldName) +{ + //check if a field with the given name already exists + FieldsIndex::iterator fieldIter = mFieldsIndex.find(fieldName); + AV_ASSERT(fieldIter == mFieldsIndex.end()); + + if (field != 0) + { + field->clone()->bind(this, fieldName, true); + } + else + { + AVANGO_LOG(logger,logging::WARN , "invalid field"); + } +} + +/* virtual */ +void +av::FieldContainer::removeField(unsigned int index) +{ + AV_ASSERT(index < mFields.size()); + + //get the FieldInfo object + FieldInfo fInfo = mFields[index]; + + //disconnect + fInfo.mField->disconnect(); + fInfo.mField->disconnectAuditors(); + + unsigned int numFields = mFields.size()-1; + if(numFields > 0) { + //relocate the last field into the freed entry + mFields[index] = mFields[numFields]; + mFieldsIndex[mFields[index].mName] = index; + + //update the field id + mFields[index].mField->mIndex = index; + } + + //remove last entry. + mFields.erase(mFields.end()-1); + mFieldsIndex.erase(fInfo.mName); + + mFlags.mFieldsCalculated = false; + +} + +/* virtual */ +void +av::FieldContainer::removeDynamicField(const std::string& fieldName) +{ + //get the field id + FieldsIndex::iterator fieldIter = mFieldsIndex.find(fieldName); + AV_ASSERT(fieldIter != mFieldsIndex.end()); + + //get the FieldInfo object + Field * field = mFields[fieldIter->second].mField; + + //unbind the field. Unset the internal reference of the field to the FieldContainer + field->unbind(); + + //delete the removed field + delete field; + +} + +/* virtual */ bool +av::FieldContainer::hasField(const std::string& name) +{ + FieldsIndex::const_iterator iter = mFieldsIndex.find(name); + return (iter != mFieldsIndex.end()); +} + +av::Field* +av::FieldContainer::getField(unsigned int index) +{ + return (index < mFields.size() ? mFields[index].mField : 0); +} + +av::Field* +av::FieldContainer::getField(const std::string& name) +{ + FieldInfo *field_info = getFieldInfo(name); + return (field_info != 0 ? field_info->mField : 0); +} + +const std::string& +av::FieldContainer::getFieldName(unsigned int index) +{ + return (index < mFields.size() ? mFields[index].mName : empty_string); +} + +av::FieldContainer::IDType +av::FieldContainer::getId() const +{ + return mId; +} + +bool +av::FieldContainer::needsEvaluation() const +{ + return mFlags.mNeedsEvaluation; +} + +void +av::FieldContainer::callEvaluate() +{ + if (!mFlags.mIsEvaluating) + { + if (mEvaluateId != sEvaluateId) + { + mFlags.mIsEvaluating = true; + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("callEvaluate: evaluating dependencies of '%1%' @0x%2%.") % getTypeId().getName() % this)); + + // Evaluate field containers that our own fields depend on +// FieldPtrVec &fields = getFields(); +// for (FieldPtrVec::iterator field_it = fields.begin(); field_it != fields.end(); ++field_it) +// { +// (*field_it)->evaluateDependencies(); +// } + + // Evaluate field containers that our own fields depend on + //TODO Changed for simplicity + std::for_each (getFields().begin(), getFields().end(), std::mem_fun(&Field::evaluateDependencies)); + + if (mFlags.mNeedsEvaluation) + { + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("callEvaluate: evaluating '%1%' @0x%2% (%3$07.3lf).") % getTypeId().getName() % this % mLastChange)); + + // evaluate for local sideeffect + this->evaluateLocalSideEffect(); + + // evaluate for (possibly) global sideeffect + // (in the distr. case only if "owns" the container, + // i.e. is the original creator + if (isOwned()) + { + this->evaluate(); + } + + //reset the status of the fields + std::for_each (getFields().begin(), getFields().end(), std::mem_fun(&Field::reset)); + + mFlags.mNeedsEvaluation = mFlags.mAlwaysEvaluate; + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("callEvaluate: '%1%' @0x%2% evaluated.") % getTypeId().getName() % this)); + + } + + mEvaluateId = sEvaluateId; + mFlags.mIsEvaluating = false; + } + } + else + { + AVANGO_LOG(logger,logging::WARN , boost::str(boost::format("callEvaluate: detected evaluation loop: '%1%', %2%.") % getTypeId().getName() % Name.getValue())); + } +} + +double +av::FieldContainer::lastChange() const +{ + return mLastChange; +} + +void +av::FieldContainer::scheduleForEvaluation() +{ + mFlags.mNeedsEvaluation = true; + + if (!mFlags.mIsInEvaluationList && mFlags.mAllowScheduling) + { + evaluation_list.push_back(Link(this)); + mFlags.mIsInEvaluationList = true; + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("scheduleForEvaluation: '%1%' @0x%2% scheduled, list size %3%.") % getTypeId().getName() % this % evaluation_list.size())); + } +} + +void +av::FieldContainer::touch(bool from_net) +{ + if (!from_net) + { +#if defined(AVANGO_DISTRIBUTION_SUPPORT) + notifyLocalChange(); +#endif + } + + scheduleForEvaluation(); +} + +void +av::FieldContainer::enableNotify(bool on) +{ + std::for_each (getFields().begin(), getFields().end(), + std::bind2nd(std::mem_fun(&Field::enableNotify), on)); +} + +void +av::FieldContainer::allowScheduling(bool on) +{ + mFlags.mAllowScheduling = on; +} + +void +av::FieldContainer::alwaysEvaluate(bool on) +{ + if (on != mFlags.mAlwaysEvaluate) + { + mFlags.mAlwaysEvaluate = on; + + AVANGO_LOG(logger,logging::INFO , boost::str(boost::format("alwaysEvaluate: %1%abled 'alwaysEvaluate' for '%2%' @0x%3%") % (on ? "en" : "dis") % getTypeId().getName() % this)); + + touch(); + } +} + +void +av::FieldContainer::evaluateDependency(FieldContainer& dependency) +{ + if (mFlags.mIsEvaluating) + dependency.callEvaluate(); + else + AVANGO_LOG(logger,logging::WARN , "evaluateDependency: called from outside of evaluate"); +} + +/* virtual */ void +av::FieldContainer::getNameCB(const av::SFString::GetValueEvent& event) +{ + *(event.getValuePtr()) = ContainerPool::getNameByInstance(this); +} + +/* virtual */ void +av::FieldContainer::setNameCB(const av::SFString::SetValueEvent& event) +{ + ContainerPool::setNameForInstance(this, event.getValue()); +} + +/* static */ unsigned int +av::FieldContainer::getNumberOfContainersToEvaluate() +{ + return evaluation_list.size(); +} + +/* static */ void +av::FieldContainer::evaluateAllContainers() +{ + if (!evaluation_list.empty()) + { + // create new evaluate traversal id + ++sEvaluateId; + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("evaluateAllContainers: %1% in evaluation list") % evaluation_list.size())); + + FieldContainerList::iterator current_container = evaluation_list.begin(); + while (current_container != evaluation_list.end()) + { + if (!(*current_container).isValid()) + { + AVANGO_LOG(logger,logging::WARN , "evaluateAllContainers: skipping invalid container"); + } + else + { + // only evaluate if the evaluation_list has not the last reference to the object + // TODO: evaluation_list should use weak pointers + if ((*current_container)->referenceCount() > 1) + { + (*current_container)->callEvaluate(); + + // setup for reschedule if requested or needed + if ((*current_container)->mFlags.mNeedsEvaluation) + { + ++current_container; + continue; + } + } + } + + (*current_container)->mFlags.mIsInEvaluationList = false; + current_container = evaluation_list.erase(current_container); + } + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("evaluateAllContainers: %1% rescheduled") % evaluation_list.size())); + + } +} + +/* static */ void +av::FieldContainer::unscheduleEvaluationForAllContainers() +{ + evaluation_list.clear(); +} + +unsigned int +av::FieldContainer::getNumWriteableFields() +{ + int count = 0; + FieldPtrVec::const_iterator current = getFields().begin(); + FieldPtrVec::const_iterator past_of_end = getFields().end(); + + while (current != past_of_end) { + if ((*current)->isWritable()) + ++count; + + ++current; + } + + return count; +} + +void +av::FieldContainer::disconnectAllFields() +{ + FieldPtrVec& fields = getFields(); + for (FieldPtrVec::iterator eachField = fields.begin(); + eachField != fields.end(); + ++eachField) + { + (*eachField)->disconnect(); + } +} + +std::vector& +av::FieldContainer::getFields() +{ + if (!mFlags.mFieldsCalculated) { + FieldPtrVec emptyVec(mFields.size()); + mFieldPtrs.swap(emptyVec); + std::transform(mFields.begin(), mFields.end(), mFieldPtrs.begin(), + boost::bind(&FieldInfo::mField, _1)); + mFlags.mFieldsCalculated = true; + } + return mFieldPtrs; +} + +bool +av::FieldContainer::getFieldRef(const std::string& name, av::FieldRef& fr) +{ + Field* f = getField(name); + if (f) { + fr.mFC = this; + fr.mFi = f->getIndex(); + return true; + } else { + return false; + } +} + +void +av::FieldContainer::evaluate() +{ + AVANGO_LOG(logger,logging::TRACE , "evaluated: called"); +} + +void +av::FieldContainer::evaluateLocalSideEffect() +{ + AVANGO_LOG(logger,logging::TRACE , "evaluteLocalSideEffect: called"); +} + +void +av::FieldContainer::fieldHasChanged(const Field& /*field*/) +{ + AVANGO_LOG(logger,logging::TRACE , "fieldHasChanged: called"); +} + +void +av::FieldContainer::fieldHasChangedLocalSideEffect(const Field& /*field*/) +{ + AVANGO_LOG(logger,logging::TRACE , "fieldHasChangedLocalSideEffect: called"); +} + +void +av::FieldContainer::fieldChanged(const Field& field, bool from_net) +{ + // local side effects are always evaluated + this->fieldHasChangedLocalSideEffect(field); + + // call the virtual function to let user code handle this + if (isOwned()) + { + this->fieldHasChanged(field); + } + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("FieldContainer::fieldChanged: '%1%' @0x%2%: field '%3%' changed %4%.") % getTypeId().getName() % this % field.getName() % (from_net? "from net" : "locally") )); + + // TODO timestamp for last change + // mLastChange = pfGetFrameTimeStamp(); + + // queue for evaluation + touch(from_net); +} + +void +av::FieldContainer::read(InputStream& is) +{ + FieldPtrVec& fields = getFields(); + + if (is.isBinaryEnabled()) + { + // read number of fields + uint32_t count; + + is.read((char*) &count, sizeof(count)); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("read: reading %1% fields") % count)); + + for (unsigned int i = 0; i < count; i++) + { + // read index of this field + uint32_t index = 0; + + is.read((char*) &index, sizeof(index)); + + AV_ASSERT(index < fields.size()); + + // read field value + is >> fields[index]; + fields[index]->readConnection(is); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format(" %1%") % fields[index]->getName())); + + } + } + else + { + // read number of fields + int count; + + is >> count; + for (int i=0; i> name; + + // read field value + Field* field = getField(name); + is >> field; + field->readConnection(is); + } + } +} + +#if defined(AVANGO_DISTRIBUTION_SUPPORT) +/* virtual */ void +av::FieldContainer::push(av::Msg& msg) +{ + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("push: pushing a %1% (%2%)") % getTypeId().getName() % typeid(*this).name() )); + + FieldPtrVec& fields = getFields(); + unsigned int fields_pushed = 0; + FieldPtrVec::iterator i; + + for (i=fields.begin(); i!=fields.end(); ++i) { + Field* field = (*i); + + if (msg.getType() == Msg::relative) { + // push only changed fields + if (field->isDistributable() && + field->mFlags.needsDistribution) { + av_pushMsg(msg, field); + av_pushMsg(msg, field->getIndex()); + fields_pushed++; + field->mFlags.needsDistribution = false; + } + } else { + // push all fields + if (field->isDistributable()) { + av_pushMsg(msg, field); + av_pushMsg(msg, field->getIndex()); + fields_pushed++; + } + } + } + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("push: %1% of %2% fields.") % fields_pushed % this->getNumFields())); + + av_pushMsg(msg, fields_pushed); +} + +/* virtual */ void +av::FieldContainer::pop(av::Msg& msg) +{ + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("pop: popping a %1% (%2%).") % getTypeId().getName() % typeid(*this).name())); + + unsigned int num_fields; + av_popMsg(msg, num_fields); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("pop: %1% of %2% fields.") % num_fields % this->getNumFields())); + + AV_ASSERT(num_fields <= this->getNumFields()); + + for (unsigned int i=0; igetNumFields()); + Field* field = getField(index); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("pop: (index %1%:%2%)") % index % field->getTypeId().getName())); + + av_popMsg(msg, field); + } +} +#endif // #if defined(AVANGO_DISTRIBUTION_SUPPORT) + +void +av::FieldContainer::write(OutputStream& os) +{ + FieldPtrVec& fields = getFields(); + + if (os.isBinaryEnabled()) + { + // write number of fields + uint32_t size = getNumWriteableFields(); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("write: writing %1% fields") % size)); + + os.write((char*) &size, sizeof(size)); + + FieldPtrVec::iterator i; + + for (i=fields.begin(); i!=fields.end(); i++) + { + if ((*i)->isWritable()) + { + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format(" %1%") % (*i)->getName())); + + // write index of this field + uint32_t index = (*i)->getIndex(); + os.write((char*) &index, sizeof(index)); + // write the field value + (*i)->write(os); + // write possible connections + (*i)->writeConnection(os); + } + } + } + else + { + // write number of fields + +#if !defined(_WIN32) + os << getNumWriteableFields() << std::endl; +#else + // cl of VS 8 apparently not able to resolve os << bla. Or is this resolved with Service Pack 1 ?! + os.operator<<(getNumWriteableFields()); + os.operator<<(std::endl); +#endif + + FieldPtrVec::iterator i; + + for (i=fields.begin(); i!=fields.end(); i++) + { + if ((*i)->isWritable()) { + // write name of this field + os << (*i)->getName(); + (std::ostream&) os << ' '; + // write the field value + (*i)->write(os); + os << std::endl; + // write possible connections + (*i)->writeConnection(os); + os << std::endl; + } + } + } +} diff --git a/avango-core/src/avango/nodes/ObjectValue.cpp b/avango-core/src/avango/nodes/ObjectValue.cpp new file mode 100644 index 00000000..e947407c --- /dev/null +++ b/avango-core/src/avango/nodes/ObjectValue.cpp @@ -0,0 +1,47 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#include + +// specialization of the members + +template <> const std::string +av::ObjectValue::sClassTypeName = "av::BoolObject"; + +template <> const std::string +av::ObjectValue::sClassTypeName = "av::IntObject"; + +template <> const std::string +av::ObjectValue::sClassTypeName = "av::UIntObject"; + +template <> const std::string +av::ObjectValue::sClassTypeName = "av::FloatObject"; + +template <> const std::string +av::ObjectValue::sClassTypeName = "av::DoubleObject"; + +template <> const std::string +av::ObjectValue >::sClassTypeName = "av::FieldContainerObject"; + +template <> const std::string +av::ObjectValue::sClassTypeName = "av::StringObject"; diff --git a/avango-core/src/avango/nodes/Typed.cpp b/avango-core/src/avango/nodes/Typed.cpp new file mode 100644 index 00000000..03b0a7ad --- /dev/null +++ b/avango-core/src/avango/nodes/Typed.cpp @@ -0,0 +1,93 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include "avango/Typed.h" + +// includes, system + +#include +#include + +// includes, project + +#include +#include + +#define AV_TYPED_DEBUG +#undef AV_TYPED_DEBUG + +// internal unnamed namespace + +namespace +{ + // types, internal + + // variables, internal + + av::logging::Logger& logger(av::logging::Logger::getLogger("av::Typed")); + + // functions, internal + +} // namespace + +// variables, exported + +// functions, exported + +/* static */ av::Type av::Typed::sClassTypeId = av::Type::badType(); + +av::Typed::Typed() +{} + +/* virtual */ +av::Typed::~Typed() +{} + +/* static */ void +av::Typed::initClass() +{ + if (Type::badType() == sClassTypeId) { + sClassTypeId = Type::createAbstractType(Type::badType(), "av::Typed", + false); + + AV_ASSERT(Type::badType() != sClassTypeId); + + } +} + +/* static */ av::Type +av::Typed::getClassTypeId() +{ + if (Type::badType() == sClassTypeId) { + + AVANGO_LOG(logger,logging::WARN , "getClassTypeId(): returning 'bad_type'!") + + return Type::badType(); + } + + return sClassTypeId; +} diff --git a/avango-core/src/avango/nodes/tests/MockFieldContainer.cpp b/avango-core/src/avango/nodes/tests/MockFieldContainer.cpp new file mode 100644 index 00000000..08e814ac --- /dev/null +++ b/avango-core/src/avango/nodes/tests/MockFieldContainer.cpp @@ -0,0 +1,49 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "MockFieldContainer.h" + +AV_FC_DEFINE(MockFieldContainer); + +MockFieldContainer::MockFieldContainer() +{ + AV_FC_ADD_FIELD(AnIntField, 0); + AV_FC_ADD_FIELD(ADoubleField, 0.); + AV_FC_ADD_FIELD(AStringField, "value"); + AV_FC_ADD_FIELD(AnIntMultiField, std::vector()); +} + +/* virtual */ MockFieldContainer::~MockFieldContainer() +{} + +/* static */ void MockFieldContainer::initClass() +{ + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, MockFieldContainer, true); + } +} + diff --git a/avango-core/src/avango/nodes/tests/MockFieldContainer.h b/avango-core/src/avango/nodes/tests/MockFieldContainer.h new file mode 100644 index 00000000..9b05870d --- /dev/null +++ b/avango-core/src/avango/nodes/tests/MockFieldContainer.h @@ -0,0 +1,59 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_MOCKFIELDCONTAINER_H) +#define AV_MOCKFIELDCONTAINER_H + +#include +#include + +/** + * MockFieldContainer, illustrates the way of implementing an Avango FieldContainer. + */ +class MockFieldContainer : public av::FieldContainer +{ + AV_FC_DECLARE(); + +public: + + /** + * Constructor + */ + MockFieldContainer(); + + /** + * Destructor + */ + virtual ~MockFieldContainer(); + +private: + + av::SFInt AnIntField; + av::SFDouble ADoubleField; + av::SFString AStringField; + av::MFInt AnIntMultiField; +}; + +#endif // #if !defined(AV_MOCKFIELDCONTAINER_H) diff --git a/avango-core/src/avango/nodes/tests/TestAbstractNode.cpp b/avango-core/src/avango/nodes/tests/TestAbstractNode.cpp new file mode 100644 index 00000000..6769431d --- /dev/null +++ b/avango-core/src/avango/nodes/tests/TestAbstractNode.cpp @@ -0,0 +1,138 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +// include i/f header + +// includes, system + +// includes, project + +#include +#include +#include +#include + +// variables, exported + +// internal unnamed namespace + +namespace { + using namespace av; + + class AbstractNode : public av::FieldContainer { + AV_FC_DECLARE_ABSTRACT(); + + public: + + AbstractNode(); + virtual ~AbstractNode(); + + MFFloat FloatField; + + virtual void pureVirtualFunction() = 0; + + }; + + AV_FC_DEFINE_ABSTRACT(AbstractNode); + + AbstractNode::AbstractNode() + { + AV_FC_ADD_FIELD(FloatField, MFFloat::ContainerType()); + } + + AbstractNode::~AbstractNode() + {} + + void + AbstractNode::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + + AV_FC_INIT_ABSTRACT(av::FieldContainer, AbstractNode, false); + } + } + + class ConcreteNode : public AbstractNode { + AV_FC_DECLARE(); + + public: + + ConcreteNode(); + virtual ~ConcreteNode(); + + MFFloat FloatField2; + + void pureVirtualFunction(); + + + }; + + AV_FC_DEFINE(ConcreteNode); + + ConcreteNode::ConcreteNode() + { + AV_FC_ADD_FIELD(FloatField2, MFFloat::ContainerType()); + } + + ConcreteNode::~ConcreteNode() + {} + + void + ConcreteNode::pureVirtualFunction() + {} + + void + ConcreteNode::initClass() + { + if (!isTypeInitialized()) + { + AbstractNode::initClass(); + + AV_FC_INIT(AbstractNode, ConcreteNode, false); + } + } + + + class InitNodeFixture + { + public: + InitNodeFixture() + { + + ConcreteNode::initClass(); + } + }; + + TEST_FIXTURE(InitNodeFixture, createConcreteNode) + { + Link node1(dynamic_cast(av::Type::createInstanceOfType("ConcreteNode"))); + + CHECK(node1.isValid()); + + } + +} // namespace + +// functions, exported diff --git a/avango-core/src/avango/nodes/tests/TestEvaluation.cpp b/avango-core/src/avango/nodes/tests/TestEvaluation.cpp new file mode 100644 index 00000000..b6e8fa9e --- /dev/null +++ b/avango-core/src/avango/nodes/tests/TestEvaluation.cpp @@ -0,0 +1,95 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#include +#include +#include +#include + +namespace +{ + class CopyNode : public av::FieldContainer + { + AV_FC_DECLARE(); + + public: + + CopyNode(); + + av::SFInt FieldIn; + av::SFInt FieldOut; + + /* virtual */ void evaluate(); + }; + + AV_FC_DEFINE(CopyNode); + + CopyNode::CopyNode() + { + AV_FC_ADD_FIELD(FieldIn, 0); + AV_FC_ADD_FIELD(FieldOut, 0); + } + + void + CopyNode::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, CopyNode, false); + } + } + + /* virtual */ void + CopyNode::evaluate() + { + FieldOut.setValue(FieldIn.getValue()); + } + + + TEST(ConstantSizeOfEvaluationLoop) + { + CopyNode::initClass(); + av::FieldContainer::unscheduleEvaluationForAllContainers(); + + av::Link node1(new CopyNode); + node1->alwaysEvaluate(true); + CHECK_EQUAL(1, av::FieldContainer::getNumberOfContainersToEvaluate()); + + av::Link node2(new CopyNode); + node2->FieldOut.touch(); + CHECK_EQUAL(2, av::FieldContainer::getNumberOfContainersToEvaluate()); + + node1->FieldIn.connectFrom(&node2->FieldOut); + node2->FieldIn.connectFrom(&node1->FieldOut, false); + + av::ApplicationInstance::get().evaluate(); + + // Node 1 will always be evaluated and Node 2 should be dirty from + // weak field connection + CHECK_EQUAL(2, av::FieldContainer::getNumberOfContainersToEvaluate()); + + node1->FieldIn.disconnect(); + node2->FieldIn.disconnect(); + } +} diff --git a/avango-core/src/avango/nodes/tests/TestEvaluationOrder.cpp b/avango-core/src/avango/nodes/tests/TestEvaluationOrder.cpp new file mode 100644 index 00000000..3c3a8426 --- /dev/null +++ b/avango-core/src/avango/nodes/tests/TestEvaluationOrder.cpp @@ -0,0 +1,240 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#include +#include +#include +#include + +namespace +{ + class EvaluateNode : public av::FieldContainer + { + AV_FC_DECLARE(); + + public: + + EvaluateNode(); + + av::SFInt IntFieldIn; + av::SFInt IntFieldOut; + + /* virtual */ void evaluate(); + + int mEvaluateIndex; + static int sEvaluateIndex; + }; + + AV_FC_DEFINE(EvaluateNode); + + int EvaluateNode::sEvaluateIndex = 0; + + EvaluateNode::EvaluateNode() : + mEvaluateIndex(0) + { + AV_FC_ADD_FIELD(IntFieldIn, 0); + AV_FC_ADD_FIELD(IntFieldOut, 0); + } + + void + EvaluateNode::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, EvaluateNode, false); + } + } + + /* virtual */ void + EvaluateNode::evaluate() + { + mEvaluateIndex = sEvaluateIndex++; + if (IntFieldIn.getValue() < 10) + IntFieldOut.setValue(IntFieldIn.getValue() + 1); + } + + class DependantNode : public av::FieldContainer + { + AV_FC_DECLARE(); + + public: + + DependantNode(); + + av::SFContainer Dependency; + + /* virtual */ void evaluate(); + }; + + AV_FC_DEFINE(DependantNode); + + DependantNode::DependantNode() + { + AV_FC_ADD_FIELD(Dependency, 0); + } + + void + DependantNode::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, DependantNode, false); + } + } + + /* virtual */ void + DependantNode::evaluate() + { + if (Dependency.getValue().isValid()) + evaluateDependency(*Dependency.getValue()); + } + + + TEST(endlessEvaluateLoop) + { + EvaluateNode::initClass(); + + av::Link node1(new EvaluateNode); + av::Link node2(new EvaluateNode); + + node1->IntFieldIn.connectFrom(&node2->IntFieldOut); + node2->IntFieldIn.connectFrom(&node1->IntFieldOut); + + av::ApplicationInstance::get().evaluate(); + + CHECK(node1->IntFieldIn.getValue() < 3 && node2->IntFieldIn.getValue() < 3); + + node1->IntFieldIn.disconnect(); + node2->IntFieldIn.disconnect(); + } + + TEST(evaluationOrder) + { + EvaluateNode::initClass(); + EvaluateNode::sEvaluateIndex = 0; + + av::Link node1(new EvaluateNode); + av::Link node2(new EvaluateNode); + av::Link node3(new EvaluateNode); + + node2->IntFieldIn.connectFrom(&node1->IntFieldOut); + node3->IntFieldIn.connectFrom(&node2->IntFieldOut); + av::ApplicationInstance::get().evaluate(); + + EvaluateNode::sEvaluateIndex = 1; + node3->touch(); + node1->IntFieldIn.setValue(1); + av::ApplicationInstance::get().evaluate(); + + CHECK_EQUAL(1, node1->mEvaluateIndex); + CHECK_EQUAL(2, node2->mEvaluateIndex); + CHECK_EQUAL(3, node3->mEvaluateIndex); + + CHECK_EQUAL(1, node1->IntFieldIn.getValue()); + CHECK_EQUAL(2, node1->IntFieldOut.getValue()); + CHECK_EQUAL(2, node2->IntFieldIn.getValue()); + CHECK_EQUAL(3, node2->IntFieldOut.getValue()); + CHECK_EQUAL(3, node3->IntFieldIn.getValue()); + CHECK_EQUAL(4, node3->IntFieldOut.getValue()); + + node2->IntFieldIn.disconnect(); + node3->IntFieldIn.disconnect(); + } + + TEST(deactivateDependency) + { + EvaluateNode::initClass(); + EvaluateNode::sEvaluateIndex = 1; + + av::Link node1(new EvaluateNode); + av::Link node2(new EvaluateNode); + + node1->IntFieldIn.enableDependency(false); + node1->IntFieldIn.connectFrom(&node2->IntFieldOut); + node2->IntFieldIn.connectFrom(&node1->IntFieldOut); + + node1->IntFieldIn.setValue(1); + av::ApplicationInstance::get().evaluate(); + + CHECK_EQUAL(1, node1->mEvaluateIndex); + CHECK_EQUAL(2, node2->mEvaluateIndex); + + node1->IntFieldIn.disconnect(); + node2->IntFieldIn.disconnect(); + } + + TEST(weakConnectionDependency) + { + EvaluateNode::initClass(); + EvaluateNode::sEvaluateIndex = 1; + + av::Link node1(new EvaluateNode); + av::Link node2(new EvaluateNode); + + node1->IntFieldIn.connectFrom(&node2->IntFieldOut, false); + node2->IntFieldIn.connectFrom(&node1->IntFieldOut); + + node1->IntFieldIn.setValue(1); + av::ApplicationInstance::get().evaluate(); + + CHECK_EQUAL(1, node1->mEvaluateIndex); + CHECK_EQUAL(2, node2->mEvaluateIndex); + + node1->IntFieldIn.disconnect(); + node2->IntFieldIn.disconnect(); + } + + TEST(disableAllowScheduling) + { + EvaluateNode::initClass(); + EvaluateNode::sEvaluateIndex = 1; + + av::Link node(new EvaluateNode); + node->allowScheduling(false); + + node->IntFieldIn.setValue(1); + av::ApplicationInstance::get().evaluate(); + + CHECK_EQUAL(0, node->mEvaluateIndex); + } + + TEST(disableAllowSchedulingAndPull) + { + EvaluateNode::initClass(); + EvaluateNode::sEvaluateIndex = 1; + DependantNode::initClass(); + + av::Link node(new EvaluateNode); + node->allowScheduling(false); + + av::Link puller(new DependantNode); + puller->Dependency.setValue(node); + + node->IntFieldIn.setValue(1); + av::ApplicationInstance::get().evaluate(); + + CHECK_EQUAL(1, node->mEvaluateIndex); + } +} diff --git a/avango-core/src/avango/nodes/tests/TestFieldConnectionChangeInNotify.cpp b/avango-core/src/avango/nodes/tests/TestFieldConnectionChangeInNotify.cpp new file mode 100644 index 00000000..4e7f9291 --- /dev/null +++ b/avango-core/src/avango/nodes/tests/TestFieldConnectionChangeInNotify.cpp @@ -0,0 +1,122 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include + +#include +#include +#include + +#include + +namespace +{ + av::Logger& logger(av::getLogger("TestFieldConnectionChangeInNotify")); + + class MyObject : public av::IntObject + { + AV_FC_DECLARE(); + + public: + + MyObject() {} + MyObject(av::Field* field); + void fieldHasChanged(const av::Field& field); + + private: + av::Field* mOtherField; + }; + + AV_FC_DEFINE(MyObject); + + /* static */ void MyObject::initClass() + { + if (!isTypeInitialized()) + { + av::IntObject::initClass(); + AV_FC_INIT(av::IntObject, MyObject, true); + } + } + + MyObject::MyObject(av::Field* field) : + mOtherField(field) + { + } + + void MyObject::fieldHasChanged(const av::Field& field) + { + if (Value.getValue() == 1) + { + AVANGO_LOG(logger,av::logging::INFO , "fieldHasChanged: disconnecting from source field"); + Value.enableNotify(false); + Value.disconnectFrom(mOtherField); + Value.enableNotify(true); + } + if (Value.getValue() == 3) + { + AVANGO_LOG(logger,av::logging::INFO , "fieldHasChanged: disconnecting all fields from source field"); + Value.enableNotify(false); + mOtherField->disconnectAuditors(); + Value.enableNotify(true); + } + } + + TEST(fieldConnectionChangeInNotify) + { + MyObject::initClass(); + + av::Link src(new av::IntObject); + av::Link dst1(new MyObject(&src->Value)); + av::Link dst2(new av::IntObject); + + src->Value.setValue(0); + dst1->Value.setValue(0); + dst2->Value.setValue(0); + + dst1->Value.connectFrom(&src->Value); + dst2->Value.connectFrom(&src->Value); + + src->Value.setValue(1); + CHECK_EQUAL(1, dst1->Value.getValue()); + CHECK_EQUAL(1, dst2->Value.getValue()); + + src->Value.setValue(2); + CHECK_EQUAL(1, dst1->Value.getValue()); + CHECK_EQUAL(2, dst2->Value.getValue()); + + dst1->Value.connectFrom(&src->Value); + + src->Value.setValue(3); + CHECK_EQUAL(3, dst1->Value.getValue()); + CHECK_EQUAL(3, dst2->Value.getValue()); + + src->Value.setValue(4); + CHECK_EQUAL(3, dst1->Value.getValue()); + CHECK_EQUAL(3, dst2->Value.getValue()); + + av::ApplicationInstance::get().evaluate(); + } +} diff --git a/avango-core/src/avango/nodes/tests/TestFieldContainer.cpp b/avango-core/src/avango/nodes/tests/TestFieldContainer.cpp new file mode 100644 index 00000000..4009780d --- /dev/null +++ b/avango-core/src/avango/nodes/tests/TestFieldContainer.cpp @@ -0,0 +1,105 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#include "MockFieldContainer.h" +#include +#include +#include + +namespace +{ + TEST(TypeIdOfFields) + { + MockFieldContainer::initClass(); + + av::Link fc = + dynamic_cast(av::Type::createInstanceOfType("MockFieldContainer")); + CHECK(&*fc != 0 ); + av::Field& self_p = *fc->getField("AnIntField"); + CHECK(&self_p != 0 ); + } + + using namespace av; + + class TestNode : public av::FieldContainer { + AV_FC_DECLARE(); + + public: + + TestNode(); + virtual ~TestNode(); + + SFFloat FloatField; + }; + + AV_FC_DEFINE(TestNode); + + TestNode::TestNode() + { + AV_FC_ADD_FIELD(FloatField, 0.0f); + } + + TestNode::~TestNode() + {} + + void + TestNode::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + + AV_FC_INIT(av::FieldContainer, TestNode, false); + } + } + + class InitNodeFixture + { + public: + InitNodeFixture() + { + + TestNode::initClass(); + } + }; + + TEST_FIXTURE(InitNodeFixture, getFieldWithInvalidArguments) + { + Link node(new TestNode); + + CHECK(node->getField("NonExistingField") == 0); + CHECK(node->getField(15u) == 0); + } + + TEST_FIXTURE(InitNodeFixture, disconnectAllFieldsWorks) + { + Link node1(new TestNode); + Link node2(new TestNode); + + node2->FloatField.connectFrom(&(node1->FloatField)); + + CHECK_EQUAL(1u, node2->FloatField.getNumberOfConnectedFields()); + node2->disconnectAllFields(); + CHECK_EQUAL(0u, node2->FloatField.getNumberOfConnectedFields()); + } +} diff --git a/avango-core/src/avango/nodes/tests/TestNodes.cpp b/avango-core/src/avango/nodes/tests/TestNodes.cpp new file mode 100644 index 00000000..939baff9 --- /dev/null +++ b/avango-core/src/avango/nodes/tests/TestNodes.cpp @@ -0,0 +1,37 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + + +#include +#include + +#include + +int main() +{ + av::getRootLogger().addConsoleAppender(); + av::ApplicationInstance::get(); + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/nodes/tests/TestUnref.cpp b/avango-core/src/avango/nodes/tests/TestUnref.cpp new file mode 100644 index 00000000..9899e7dd --- /dev/null +++ b/avango-core/src/avango/nodes/tests/TestUnref.cpp @@ -0,0 +1,146 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +// $Id$ + +// include i/f header + +// includes, system + +// includes, project + +#include +#include +#include +#include + +// variables, exported + +// internal unnamed namespace + +namespace { + using namespace av; + + class Lifetime : public av::FieldContainer { + AV_FC_DECLARE(); + + public: + + Lifetime(); + virtual ~Lifetime(); + + static bool is_living; + }; + + bool Lifetime::is_living = false; + + AV_FC_DEFINE(Lifetime); + + Lifetime::Lifetime() + { + is_living = true; + } + + Lifetime::~Lifetime() + { + is_living = false; + } + + void + Lifetime::initClass() + { + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + + AV_FC_INIT(av::FieldContainer, Lifetime, true); + } + } + + class InitNodeFixture + { + public: + InitNodeFixture() + { + Lifetime::initClass(); + } + }; + + TEST_FIXTURE(InitNodeFixture, UsingLinks) + { + CHECK(!Lifetime::is_living); + Link node(dynamic_cast(av::Type::createInstanceOfType("Lifetime"))); + CHECK(node.isValid()); + CHECK(Lifetime::is_living); + } + + TEST_FIXTURE(InitNodeFixture, ManualUnrefing) + { + CHECK(!Lifetime::is_living); + Lifetime* node(dynamic_cast(av::Type::createInstanceOfType("Lifetime"))); + CHECK(0 != node); + CHECK(Lifetime::is_living); + node->reference(); + node->unreference(); + CHECK(!Lifetime::is_living); + } + + TEST_FIXTURE(InitNodeFixture, ManualUnrefingWithoutDeletion) + { + CHECK(!Lifetime::is_living); + Lifetime* node(dynamic_cast(av::Type::createInstanceOfType("Lifetime"))); + CHECK(0 != node); + CHECK(Lifetime::is_living); + node->reference(); + + node->unreferenceWithoutDeletion(); + CHECK(Lifetime::is_living); + + node->reference(); + node->unreference(); + CHECK(!Lifetime::is_living); + } + + TEST_FIXTURE(InitNodeFixture, ManualUnrefingWithFloatingRefs) + { + CHECK(!Lifetime::is_living); + Lifetime* node(dynamic_cast(av::Type::createInstanceOfType("Lifetime"))); + CHECK(0 != node); + CHECK(Lifetime::is_living); + + node->reference(); + node->setFloatingReference(); + node->unreference(); + CHECK(Lifetime::is_living); + + node->reference(); + node->unreference(); + CHECK(!Lifetime::is_living); + } + + +} // namespace + +// functions, exported + +// $Id$ diff --git a/avango-core/src/avango/streams/InputStream.cpp b/avango-core/src/avango/streams/InputStream.cpp new file mode 100644 index 00000000..0761fbc5 --- /dev/null +++ b/avango-core/src/avango/streams/InputStream.cpp @@ -0,0 +1,212 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +av::InputStream::InputStream() : + std::istream(0), + mBinary(false), + mReader(0) +{} + +av::InputStream::InputStream(std::istream& is) : + std::istream(is.rdbuf()), + mBinary(false), + mReader(0) +{} + +av::InputStream::InputStream(std::streambuf* sb) : + std::istream(sb), + mBinary(false), + mReader(0) +{} + +av::InputStream& +av::InputStream::operator=(std::istream& is) +{ + (void) rdbuf(is.rdbuf()); + return *this; +} + +av::InputStream& +av::InputStream::operator=(std::streambuf* sb) +{ + (void) rdbuf (sb); + return *this; +} + +void +av::InputStream::enableBinary(bool on) +{ + mBinary = on; +} + +bool +av::InputStream::isBinaryEnabled() const +{ + return mBinary; +} + +void +av::InputStream::setReader(av::Reader* reader) +{ + mReader = reader; +} + +av::Reader* +av::InputStream::getReader() +{ + return mReader; +} + +av::InputStream& av::operator>>(av::InputStream& is, int16_t& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, 4); + } else { + (std::istream&) is >> value; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, uint16_t& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, 4); + } else { + (std::istream&) is >> value; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, int32_t& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, 4); + } else { + (std::istream&) is >> value; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, uint32_t& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, 4); + } else { + (std::istream&) is >> value; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, int64_t& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, 8); + } else { + int32_t tmp; + (std::istream&) is >> tmp; + value = tmp; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, uint64_t& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, 8); + } else { + uint32_t tmp; + (std::istream&) is >> tmp; + value = tmp; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, float& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, sizeof(value)); + } else { + (std::istream&) is >> value; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, double& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, sizeof(value)); + } else { + (std::istream&) is >> value; + } + return is; +} + +av::InputStream& av::operator>>(av::InputStream& is, bool& value) +{ + if (is.isBinaryEnabled()) { + is.read((char*) &value, sizeof(value)); + } else { + (std::istream&) is >> value; + } + return is; +} + +av::InputStream& +av::operator>>(av::InputStream& is, std::string& value) +{ + char str[1024]; + if (is.isBinaryEnabled()) + { + int size = 0; + is.read((char*) &size, sizeof(int)); + if (is && size) + is.read(str, size); + str[size] = '\0'; + value = str; + } + else + { + char chr; + (std::istream&)is >> chr; + AV_ASSERT(chr == '"'); + std::ios_base::fmtflags old_flags = is.flags(); + is.unsetf(std::istream::skipws); + int size = -1; + do { + (std::istream&)is >> chr; + if (!is) break; + size ++; + str[size] = chr; + } while (chr != '"'); + str[size] = '\0'; + is.flags(old_flags); + value = str; + } + return is; +} diff --git a/avango-core/src/avango/streams/OutputStream.cpp b/avango-core/src/avango/streams/OutputStream.cpp new file mode 100644 index 00000000..71827456 --- /dev/null +++ b/avango-core/src/avango/streams/OutputStream.cpp @@ -0,0 +1,208 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include + + +av::OutputStream::OutputStream() : + std::ostream(0), + mWriteAction(0), + mBinary(false) +{} + +av::OutputStream::OutputStream(std::ostream& os) : + std::ostream(os.rdbuf()), + mWriteAction(0), + mBinary(false) +{} + +av::OutputStream::OutputStream(std::streambuf* sb) : + std::ostream(sb), + mWriteAction(0), + mBinary(false) +{} + +av::OutputStream& +av::OutputStream::operator=(std::ostream& os) +{ + (void) rdbuf(os.rdbuf()); + return *this; +} + +av::OutputStream& +av::OutputStream::operator=(std::streambuf* sb) +{ + (void) rdbuf(sb); + return *this; +} + +void +av::OutputStream::enableBinary(bool on) +{ + mBinary = on; +} + +bool +av::OutputStream::isBinaryEnabled() const +{ + return mBinary; +} + +void +av::OutputStream::setWriteAction(av::WriteAction* writeAction) +{ + mWriteAction = writeAction; +} + +av::WriteAction* +av::OutputStream::getWriteAction() +{ + return mWriteAction; +} + +av::OutputStream& +av::endl(av::OutputStream& os) +{ + std::endl(os); + return os; +} + +av::OutputStream& +av::flush(av::OutputStream& os) +{ + std::flush(os); + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const int16_t& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, 4); + } else { + (std::ostream&) os << value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const uint16_t& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, 4); + } else { + (std::ostream&) os << value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const int32_t& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, 4); + } else { + (std::ostream&) os << value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const uint32_t& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, 4); + } else { + (std::ostream&) os << value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const int64_t& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, 8); + } else { + (std::ostream&) os << (int32_t) value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const uint64_t& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, 8); + } else { + (std::ostream&) os << (uint32_t) value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const float& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, sizeof(value)); + } else { + (std::ostream&) os << value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const double& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, sizeof(value)); + } else { + (std::ostream&) os << value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const bool& value) +{ + if (os.isBinaryEnabled()) { + os.write((const char*) &value, sizeof(value)); + } else { + (std::ostream&) os << value; + } + return os; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const std::string& value) +{ + if (os.isBinaryEnabled()) { + if (value.c_str()) { + int length = std::strlen(value.c_str()); + os.write((char*) &length, sizeof(length)); + os.write(value.c_str(), length); + } else { + int length = 0; + os.write((char*) &length, sizeof(length)); + } + } else { + (std::ostream&)os << '"'; + if (value.c_str()) + os.write(value.c_str(), std::strlen(value.c_str())); + (std::ostream&)os << '"'; + } + return os; +} diff --git a/avango-core/src/avango/streams/Reader.cpp b/avango-core/src/avango/streams/Reader.cpp new file mode 100644 index 00000000..20f7b783 --- /dev/null +++ b/avango-core/src/avango/streams/Reader.cpp @@ -0,0 +1,184 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::Reader")); +} + +av::Reader::Reader() : + mBinary(true) +{} + +av::Reader::~Reader() +{} + +av::Base* +av::Reader::readObject(av::InputStream& stream) +{ + // read object type + std::string type_str; + stream >> type_str; + + AVANGO_LOG(logger, logging::INFO, boost::str(boost::format("readObject: type: %1%") % type_str)); + + if (stream.eof()) + { + AVANGO_LOG(logger, logging::WARN, "readObject: eof encountered"); + return 0; + } + + Link object = (Base*) Type::createInstanceOfType(type_str); + + if (!object.isValid()) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("readObject: illegal type name '%1%'") % type_str)); + return 0; + } + + // read object id + std::string obj_id; + stream >> obj_id; + + AVANGO_LOG(logger, logging::INFO, boost::str(boost::format("readObject: id: ") % obj_id)); + + if (stream.fail() || stream.bad()) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("readObject: error reading object id for '%1%'") % type_str)) + return 0; + } + + // read object + stream >> object.getPtr(); + + if (stream.fail() || stream.bad()) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("readObject: error reading object of type '%1%'") % type_str)); + return 0; + } + + mObjectMap.insert(StringBaseMap::value_type(obj_id, object)); + + return object.getPtr(); +} + +av::Base* +av::Reader::readFromFile(const std::string& filename) +{ + std::ifstream* file = new std::ifstream(filename.c_str()); + + if (!file || file->bad()) + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("readFromFile: can't open file '%1%'") % filename)); + return 0; + } + + AVANGO_LOG(logger, logging::INFO, boost::str(boost::format("readFromFile: '%1%'") % filename)); + + InputStream* stream = new InputStream(*file); + + stream->enableBinary(isBinaryEnabled()); + stream->setReader(this); + + mObjectMap.clear(); + mConnectionMap.clear(); + + // recursively read object hierachy + Base* root = readObject(*stream); + + delete stream; + delete file; + + // resolve pending connections + for (ConnectionMap::iterator i = mConnectionMap.begin(); + i != mConnectionMap.end(); ++i) + { + Field* to_field = (*i).first; + std::string from_id = (*i).second.first; + int from_index = (*i).second.second; + + Base* from_base = lookupObject(from_id); + if (from_base && + from_base->getTypeId().isOfType(FieldContainer::getClassTypeId())) + { + FieldContainer* fc = (FieldContainer*) from_base; + Field* from_field = fc->getField(from_index); + + to_field->connectFrom(from_field); + + } + else + { + AVANGO_LOG(logger, logging::WARN, boost::str(boost::format("readFromFile: error resolving connection from object '%1%'!") % from_id)); + } + } + + AVANGO_LOG(logger, logging::INFO, boost::str(boost::format("readFromFile: %1% connections resolved!") % mConnectionMap.size())); + + mObjectMap.clear(); + mConnectionMap.clear(); + return root; +} + +av::Base* +av::Reader::lookupObject(const std::string& id) +{ + StringBaseMap::iterator i = mObjectMap.find(id); + + if (i != mObjectMap.end()) { + return (*i).second.getPtr(); + } + + return 0; +} + +void +av::Reader::addConnection(av::Field* toField, const std::string& fromId, int fromIndex) +{ + mConnectionMap.insert(ConnectionMap::value_type(toField, + std::pair(fromId, fromIndex))); +} + +void +av::Reader::enableBinary(bool bin) +{ + mBinary = bin; +} + +bool +av::Reader::isBinaryEnabled() +{ + return mBinary; +} diff --git a/avango-core/src/avango/support/Assert.cpp b/avango-core/src/avango/support/Assert.cpp new file mode 100644 index 00000000..1626e0b1 --- /dev/null +++ b/avango-core/src/avango/support/Assert.cpp @@ -0,0 +1,67 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/Assert.h" + +#include +#include + +#if defined(_WIN32) +#include +#include +#else +#include +#define AV_DLL +#endif + +#include +#include + +AV_DLL void av::assert_fail(const char* assertion, const char* file, + unsigned int line, const char* function) +{ + std::cerr << "Assertion \"" << assertion << "\" failed in file " << file + << ", line " << line << ", function " << function << std::endl; + + const char* debugger = ::getenv("AV_DEBUGGER"); + if (debugger) + { +#if defined(_WIN32) + int my_pid = ::_getpid(); +#else + pid_t my_pid = ::getpid(); +#endif + + std::ostringstream os; + + os << debugger << " /proc/" << my_pid << "/exe " << my_pid + << std::ends; + + ::system(os.str().c_str()); + + } + + ::abort(); +} diff --git a/avango-core/src/avango/support/Semaphore.cpp b/avango-core/src/avango/support/Semaphore.cpp new file mode 100644 index 00000000..6fc285b0 --- /dev/null +++ b/avango-core/src/avango/support/Semaphore.cpp @@ -0,0 +1,80 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/Semaphore.h" + +av::Semaphore::Semaphore(unsigned int initial) +{ + mValue = initial; +} + +av::Semaphore::~Semaphore() +{} + +void +av::Semaphore::wait() +{ + boost::mutex::scoped_lock mLock(mMutex); + + --mValue; + + while (mValue < 0) { + mCondition.wait(mLock); + } +} + +int +av::Semaphore::trywait() +{ + boost::mutex::scoped_lock mLock(mMutex); + + if (mValue == 0) + { + return 0; + } + else + { + --mValue; + return 1; + } +} + +void +av::Semaphore::post() +{ + boost::mutex::scoped_lock mLock(mMutex); + + ++mValue; + mLock.unlock(); + mCondition.notify_one(); +} + +int +av::Semaphore::snapshot() +{ + boost::mutex::scoped_lock mLock(mMutex); + int result = mValue; + return result; +} diff --git a/avango-core/src/avango/types/ContainerPool.cpp b/avango-core/src/avango/types/ContainerPool.cpp new file mode 100644 index 00000000..34b20051 --- /dev/null +++ b/avango-core/src/avango/types/ContainerPool.cpp @@ -0,0 +1,375 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "avango/ContainerPool.h" + +#include + +#include +#include + +#define AVANGO_CONTAINERPOOL_DEBUG +#undef AVANGO_CONTAINERPOOL_DEBUG + +namespace +{ + av::Logger& logger(av::getLogger("av::ContainerPool")); + +} // namespace + + +/* static */ av::ContainerPool::InstancePoolType +av::ContainerPool::sContainerPool; + +/* static */ av::ContainerPool::NodeCreationCallbacksType +av::ContainerPool::sCreationCallbacks; + +/* static */ av::ContainerPool::NodeDeletionCallbacksType +av::ContainerPool::sDeletionCallbacks; + +/* static */ av::ContainerPool::FieldConnectCallbacksType +av::ContainerPool::sConnectCallbacks; + +/* static */ av::ContainerPool::FieldDisconnectCallbacksType +av::ContainerPool::sDisconnectCallbacks; + +/* static */ av::ContainerPool::FieldHasChangedCallbacksType +av::ContainerPool::sFieldHasChangedCallbacks; + +/* static */ av::ContainerPool::FieldContainerID +av::ContainerPool::sLastId = 0; + +/* static */ av::ContainerPool::NameToContainerMap +av::ContainerPool::sNameContainerMap; + +/* static */ av::ContainerPool::ContainerToNameMap +av::ContainerPool::sContainerNameMap; + + +av::ContainerPool::FieldHasChangedReg::FieldHasChangedReg(FieldHasChangedCallback callback, + av::Field* field, void* userData) : + mCb(callback), + mField(field), + mUserData(userData) +{} + +/* static */ av::ContainerPool::FieldContainerID +av::ContainerPool::registerInstance(av::FieldContainer* fieldContainer) +{ + AV_ASSERT(sLastId < sLastId+1); // check overflow + sContainerPool[++sLastId] = fieldContainer; + return sLastId; +} + +/* static */ void +av::ContainerPool::unregisterInstance(av::FieldContainer* fieldContainer) +{ + sContainerPool.erase(fieldContainer->getId()); + removeNameForInstance(fieldContainer); +} + +av::ContainerPool::NodeCreationCallbackID::NodeCreationCallbackID() : + mCallbackIter() +{} + +av::ContainerPool::NodeCreationCallbackID::NodeCreationCallbackID( + NodeCreationCallbacksType::iterator iter) : + mCallbackIter(iter) +{} + +/* static */ av::ContainerPool::NodeCreationCallbackID +av::ContainerPool::registerNodeCreationCallback(av::ContainerPool::NodeCreationCallback callback, + void* userData) +{ + sCreationCallbacks.push_back(NodeCreationCallbacksType::value_type(callback, userData)); + + NodeCreationCallbacksType::iterator last (sCreationCallbacks.end()); + + std::advance(last, -1); + + return NodeCreationCallbackID(last); +} + +/* static */ void +av::ContainerPool::unregisterNodeCreationCallback( + av::ContainerPool::NodeCreationCallbackID callbackID) +{ + sCreationCallbacks.erase(callbackID.mCallbackIter); +} + +av::ContainerPool::NodeDeletionCallbackID::NodeDeletionCallbackID() + : mCallbackIter() +{} + +av::ContainerPool::NodeDeletionCallbackID::NodeDeletionCallbackID( + NodeDeletionCallbacksType::iterator iter) : + mCallbackIter(iter) +{} + +/* static */ av::ContainerPool::NodeDeletionCallbackID +av::ContainerPool::registerNodeDeletionCallback(av::ContainerPool::NodeDeletionCallback callback, + void* userData) +{ + sDeletionCallbacks.push_back(NodeDeletionCallbacksType::value_type(callback, userData)); + + NodeDeletionCallbacksType::iterator last (sDeletionCallbacks.end()); + + std::advance(last, -1); + + return NodeDeletionCallbackID(last); +} + +/* static */ void +av::ContainerPool::unregisterNodeDeletionCallback( + av::ContainerPool::NodeDeletionCallbackID callbackID) +{ + sDeletionCallbacks.erase(callbackID.mCallbackIter); +} + +av::ContainerPool::FieldConnectCallbackID::FieldConnectCallbackID() + : mCallbackIter() +{} + +av::ContainerPool::FieldConnectCallbackID::FieldConnectCallbackID( + FieldConnectCallbacksType::iterator it) : + mCallbackIter(it) +{} + +/* static */ av::ContainerPool::FieldConnectCallbackID +av::ContainerPool::registerFieldConnectCallback(av::ContainerPool::FieldConnectCallback callback, + void* userData) +{ + sConnectCallbacks.push_back(FieldConnectCallbacksType::value_type(callback, userData)); + FieldConnectCallbacksType::iterator last (sConnectCallbacks.end()); + std::advance(last, -1); + return FieldConnectCallbackID(last); +} + +/* static */ void +av::ContainerPool::unregisterFieldConnectCallback(ContainerPool::FieldConnectCallbackID callbackID) +{ + sConnectCallbacks.erase(callbackID.mCallbackIter); +} + +av::ContainerPool::FieldDisconnectCallbackID::FieldDisconnectCallbackID() + : mCallbackIter() +{} + +av::ContainerPool::FieldDisconnectCallbackID::FieldDisconnectCallbackID( + FieldDisconnectCallbacksType::iterator it) : + mCallbackIter(it) +{} + +/* static */ av::ContainerPool::FieldDisconnectCallbackID +av::ContainerPool::registerFieldDisconnectCallback( + av::ContainerPool::FieldDisconnectCallback callback, void* userData) +{ + sDisconnectCallbacks.push_back(FieldDisconnectCallbacksType::value_type(callback, userData)); + FieldDisconnectCallbacksType::iterator last (sDisconnectCallbacks.end()); + std::advance(last, -1); + return FieldDisconnectCallbackID(last); +} + +/* static */ void +av::ContainerPool::unregisterFieldDisconnectCallback( + av::ContainerPool::FieldDisconnectCallbackID callbackID) +{ + sDisconnectCallbacks.erase(callbackID.mCallbackIter); +} + +av::ContainerPool::FieldHasChangedCallbackID::FieldHasChangedCallbackID() : + mCallbackIter() +{} + +av::ContainerPool::FieldHasChangedCallbackID::FieldHasChangedCallbackID( + FieldHasChangedCallbacksType::iterator it) : + mCallbackIter(it) +{} + +/* static */ av::ContainerPool::FieldHasChangedCallbackID +av::ContainerPool::registerFieldHasChangedCallback( + av::ContainerPool::FieldHasChangedCallback callback, Field* field, void* userData) +{ + sFieldHasChangedCallbacks.push_back(FieldHasChangedCallbacksType::value_type( + callback, field, userData)); + FieldHasChangedCallbacksType::iterator last (sFieldHasChangedCallbacks.end()); + std::advance(last, -1); + return FieldHasChangedCallbackID(last); +} + +/* static */ void +av::ContainerPool::unregisterFieldHasChangedCallback( + av::ContainerPool::FieldHasChangedCallbackID callbackID) +{ + sFieldHasChangedCallbacks.erase(callbackID.mCallbackIter); +} + +/* static */ av::FieldContainer* +av::ContainerPool::getContainerById(av::ContainerPool::FieldContainerID id) +{ + InstancePoolType::const_iterator pool_iter = sContainerPool.find(id); + + if (sContainerPool.end() != pool_iter) + { + return pool_iter->second; + } + else + { + return 0; + } +} + +/* static */ void +av::ContainerPool::setNameForInstance(av::FieldContainer* fieldContainer, const std::string& name) +{ + if (name.empty()) + { + return; // don't add nodes without names + } + + sNameContainerMap[name] = fieldContainer; + sContainerNameMap[fieldContainer] = name; +} + +/* static */ void +av::ContainerPool::setNameForInstance(av::FieldContainer* fieldContainer, const char* name) +{ + if (!name) + { + return; // don't add nodes without names + } + + sNameContainerMap[name] = fieldContainer; + sContainerNameMap[fieldContainer] = name; +} + +void +av::ContainerPool::removeNameForInstance(av::FieldContainer* fieldContainer) +{ + ContainerToNameMap::iterator foundIter = sContainerNameMap.find(fieldContainer); + + if (foundIter == sContainerNameMap.end()) + { + return; + } + + std::string name = foundIter->second; + + sContainerNameMap.erase(fieldContainer); + sNameContainerMap.erase(name); +} + +/* static */ av::FieldContainer* +av::ContainerPool::getInstanceByName(const std::string& name) +{ + NameToContainerMap::iterator foundIter; + foundIter = sNameContainerMap.find(name); + if (foundIter != sNameContainerMap.end()) + { + return foundIter->second; + } else + { + return 0; + } +} + +std::string +av::ContainerPool::getNameByInstance(av::FieldContainer* fieldContainer) +{ + ContainerToNameMap::const_iterator foundIter; + foundIter = sContainerNameMap.find(const_cast(fieldContainer)); + if (foundIter != sContainerNameMap.end()) + { + return foundIter->second; + } else + { + return std::string(); + } +} + +/*static*/ void +av::ContainerPool::notifyConnect(av::Field* field) +{ + for (FieldConnectCallbacksType::iterator iter = sConnectCallbacks.begin(); + iter != sConnectCallbacks.end(); ++iter) + { + if (iter->first) + { + (iter->first)(field, iter->second); + } + } +} + +/*static*/ void +av::ContainerPool::notifyDisconnect(av::Field* field) +{ + typedef FieldDisconnectCallbacksType::iterator iterator; + + for (FieldDisconnectCallbacksType::iterator iter = sDisconnectCallbacks.begin(); + iter != sDisconnectCallbacks.end(); ++iter) + { + if (iter->first) + { + (iter->first)(field, iter->second); + } + } +} + +/*static*/ void +av::ContainerPool::notifyFieldHasChanged(av::Field* field) +{ + for (FieldHasChangedCallbacksType::iterator iter = sFieldHasChangedCallbacks.begin(); + iter != sFieldHasChangedCallbacks.end(); ++iter) + { + if (field == iter->mField) + (iter->mCb)(field, iter->mUserData); + } +} + +/*static*/ void +av::ContainerPool::notifyCreation(av::FieldContainer* fieldContainer) +{ + for (NodeCreationCallbacksType::iterator iter = sCreationCallbacks.begin(); + iter != sCreationCallbacks.end(); ++iter) + { + if (iter->first) + { + (iter->first)(fieldContainer, iter->second); + } + } +} + +/*static*/ void +av::ContainerPool::notifyDeletion(av::FieldContainer* fieldContainer) +{ + for (NodeDeletionCallbacksType::iterator iter = sDeletionCallbacks.begin(); + iter != sDeletionCallbacks.end(); ++iter) + { + if (iter->first) + { + (iter->first)(fieldContainer, iter->second); + } + } +} diff --git a/avango-core/src/avango/types/Create.cpp b/avango-core/src/avango/types/Create.cpp new file mode 100644 index 00000000..7030c7aa --- /dev/null +++ b/avango-core/src/avango/types/Create.cpp @@ -0,0 +1,71 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include + +// includes, system + +#include +#include + +// includes, project + +#include + +// internal unnamed namespace + +namespace +{ + // types, internal + + // variables, internal + + av::Logger& logger(av::getLogger("av::Create")); + + // functions, internal + +} // namespace + +// variables, exported + +// functions, exported + +/* virtual */ +av::Create::~Create() +{} + +/* virtual */ av::Typed* +av::Create::makeInstance() const +{ + AVANGO_LOG(logger,logging::FATAL , "makeInstance(): logically 'pure virtual' function called; aborting!") + + ::abort(); + +#if defined(_WIN32) + return NULL; // and this is a special treatment to satisfy MS VS 8. +#endif +} diff --git a/avango-core/src/avango/types/Link.cpp b/avango-core/src/avango/types/Link.cpp new file mode 100644 index 00000000..d32ff32b --- /dev/null +++ b/avango-core/src/avango/types/Link.cpp @@ -0,0 +1,202 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +namespace { + av::Logger& logger(av::getLogger("av::Link")); +} + +bool +av::AnyLink::isValid() const +{ + return mBasePtr != 0; +} + +void +av::AnyLink::clear() +{ + AnyLink::setBasePtr(0); +} + +av::Base* +av::AnyLink::getBasePtr() const +{ + return mBasePtr; +} + +bool +av::AnyLink::setBasePtr(Base* base) +{ + if (base && !base->getTypeId().isOfType(mTypeId)) { + return false; + } + + if (mBasePtr) + { + mBasePtr->unreference(); + mBasePtr = 0; + } + mBasePtr = base; + if (mBasePtr) + { + mBasePtr->reference(); + } + + return true; +} + +av::AnyLink::AnyLink(av::Base* base, av::Type typeId) + : mBasePtr(0), mTypeId(typeId) +{ + setBasePtr(base); +} + +/* virtual */ +av::AnyLink::~AnyLink() +{ + if (mBasePtr) + { + mBasePtr->unreference(); + } +} + +bool +av::operator==(const av::AnyLink& a, const av::AnyLink& b) +{ + return a.getBasePtr() == b.getBasePtr(); +} + +bool +av::operator!=(const av::AnyLink& a, const av::AnyLink& b) +{ + return a.getBasePtr() != b.getBasePtr(); +} + +bool +av::operator<(const av::AnyLink& a, const av::AnyLink& b) +{ + return a.getBasePtr() < b.getBasePtr(); +} + +av::InputStream& +av::operator>>(av::InputStream& is, av::AnyLink& bl) +{ + if (is.isBinaryEnabled()) + { + if (is.getReader()) + { + char reference_flag; + (std::istream&) is >> reference_flag; + if (reference_flag == 'R') { + // object is already there, resolve reference + std::string obj_id; + is >> obj_id; + + LOG_TRACE(logger) << "operator>>(av::InputStream&, av::AnyLink&): " + << "resolving reference: " + << obj_id; + if (!bl.setBasePtr(is.getReader()->lookupObject(obj_id))) + { + AVANGO_LOG(logger,logging::WARN , boost::str(boost::format("operator>>(av::InputStream&, av::AnyLink&): type clash %1%") % obj_id)) + } + } + else + { + // object is new, load it + LOG_TRACE(logger) << "operator>>(av::InputStream&, av::AnyLink&): reading object"; + if (!bl.setBasePtr(is.getReader()->readObject(is))) + { + AVANGO_LOG(logger,logging::WARN , "operator>>(av::InputStream&, av::AnyLink&): type clash.") + } + } + } + //is.getReader()->addLink(&bl, obj_id); + } + return is; +} + +av::OutputStream& +av::operator<<(av::OutputStream& os, const av::AnyLink& bl) +{ + Base* blptr; + if (bl.isValid()) + { + blptr = bl.getBasePtr(); + } + else + { + blptr = 0; + } + + if (os.isBinaryEnabled()) + { + if (os.getWriteAction()) + { + if (os.getWriteAction()->isObjectWritten(blptr)) + { + // object is alraedy in file, only add reference + (std::ostream&) os << 'R'; + os << os.getWriteAction()->lookupObjectId(blptr); + } + else + { + // object is not written, write it. + (std::ostream&) os << 'O'; + // this will recurse write actions on base links + os.getWriteAction()->traverse(blptr); + } + } + } + else + { + if (os.getWriteAction()) + { + if (os.getWriteAction()->isObjectWritten(blptr)) + { + // object is alraedy in file, only add reference + (std::ostream&) os << 'R'; + (std::ostream&) os << " "; + (std::ostream&) os << os.getWriteAction()->lookupObjectId(blptr).c_str(); + } + else + { + // object is not written, write it. + (std::ostream&) os << 'O'; + (std::ostream&) os << " "; + // this will recurse write actions on base links + os.getWriteAction()->traverse(blptr); + } + } + } + return os; +} diff --git a/avango-core/src/avango/types/Type.cpp b/avango-core/src/avango/types/Type.cpp new file mode 100644 index 00000000..45015119 --- /dev/null +++ b/avango-core/src/avango/types/Type.cpp @@ -0,0 +1,442 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +#include "avango/Type.h" + +// includes, system + +#include +#include +#include +#include + +// includes, project + +#include +#include + +#include + +// internal unnamed namespace + +namespace +{ + // types, internal + + // variables, internal + + av::Logger& logger(av::getLogger("av::Type")); + + class TypeData { + + public: + + std::string mName; + av::Type mParent; + av::Type mType; + av::Create* mCreate; + bool mDistributable; + }; + + typedef std::vector TypeDataVec; + typedef std::map TypeMap; + + // store internal type information indexed by Type::_type_spec + TypeDataVec type_data_vec; + + // name to Type::_type_spec mapping + TypeMap type_map; + + // functions, internal + +} // namespace + +// variables, exported + +// functions, exported + +av::Type::Type() +{ + mTypeSpec.mId = 0; +} + +av::Type::Type(const Type& rhs) + : mTypeSpec(rhs.mTypeSpec) +{} + +av::Type::Type(uint32_t id) +{ + mTypeSpec.mId = id; +} + +av::Type::~Type() +{} + +const av::Type& +av::Type::operator=(const Type& rhs) +{ + mTypeSpec = rhs.mTypeSpec; + return *this; +} + +/* static */ av::Type +av::Type::badType() +{ + return Type(0); +} + +av::Type::operator uint32_t() const +{ + return mTypeSpec.mId; +} + +uint32_t +av::Type::getId() const +{ + return mTypeSpec.mId; +} + +unsigned int +av::Type::getIndex() const +{ + return mTypeSpec.mStorage.mIndex; +} + +av::Type +av::Type::getParent() const +{ + return type_data_vec[getIndex()].mParent; +} + +bool +av::Type::operator==(const Type rhs) const +{ + return mTypeSpec.mId == rhs.mTypeSpec.mId; +} + +bool +av::Type::operator!=(const Type rhs) const +{ + return !(*this == rhs); +} + +bool +av::Type::operator< (const Type rhs) const +{ + return mTypeSpec.mId < rhs.mTypeSpec.mId; +} + +bool +av::Type::isBad() const +{ + return (*this == badType()); +} + +bool +av::Type::isPublic() const +{ + return mTypeSpec.mStorage.mIsPublic; +} + +bool +av::Type::canCreate() const +{ + return mTypeSpec.mStorage.mCanCreate; +} + +const std::string& +av::Type::getName() const +{ + return type_data_vec[getIndex()].mName; +} + +/* static */ void +av::Type::init() +{ + initRegistry(); + Type bad_type = allocateNewType(false, false, false); + registerNewType("BAD_TYPE", bad_type, bad_type, 0); +} + +/* static */ void +av::Type::initRegistry() +{ + TypeDataVec emptyVec; + type_data_vec.swap(emptyVec); + type_data_vec.reserve(1); + TypeMap emptyMap; + type_map.swap(emptyMap); +} + +/* static */ av::Type +av::Type::getByName(const std::string& typeName) +{ + TypeMap::const_iterator found_type_id = type_map.find(typeName); + + if (found_type_id == type_map.end()) { + return badType(); + } + + return type_data_vec[found_type_id->second].mType; +} + + +/* static */ bool +av::Type::isTypeRegistered(const std::string& typeName) +{ + return getByName(typeName) != badType(); +} + +/* static */ av::Type +av::Type::allocateNewType(bool isPublic, bool canCreate, bool isAdaptor) +{ + Type new_type; + + new_type.mTypeSpec.mStorage.mIndex = type_data_vec.size(); + new_type.mTypeSpec.mStorage.mIsPublic = isPublic; + new_type.mTypeSpec.mStorage.mCanCreate = canCreate; + new_type.mTypeSpec.mStorage.mIsAdaptor = isAdaptor; + return new_type; +} + +/* static */ void +av::Type::registerNewType(const std::string& typeName, Type parentType, + Type newType, Create* creator) +{ + TypeData type_data; + + type_data.mName = typeName; + type_data.mParent = parentType; + type_data.mType = newType; + type_data.mCreate = creator; + + // inherit _distributable from parent class + if (parentType == badType()) { + type_data.mDistributable = false; + } else { + type_data.mDistributable = parentType.isDistributable(); + } + + type_data_vec.push_back(type_data); + + type_map[type_data.mName] = newType.getIndex(); +} + +av::Type +av::Type::createAbstractType(Type parentType, const std::string& typeName, + bool isPublic) +{ + // check for duplicates + if (isTypeRegistered(typeName)) { + AVANGO_LOG(logger,logging::FATAL , boost::str(boost::format("createAbstractType(): duplicate type name '%1%' used. exiting!") % typeName)) + + ::abort(); + + } + + // check if parent type exists + if (parentType != badType() && + parentType.getIndex() >= type_data_vec.size()) { + + AVANGO_LOG(logger,logging::WARN , boost::str(boost::format("createAbstractType(): parent '%1%' of '%2%' doesn't exist yet (parent idx: %3%, max idx: %4%), returning 'badType'") % parentType.getName() % typeName % parentType.getIndex() % type_data_vec.size())) + + return badType(); + } + + // ok, lets do it + Type new_type = allocateNewType(isPublic, false, false); + + registerNewType(typeName, parentType, new_type, 0); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("createAbstractType(): created abstract type '%s' (id: % 09d, idx: % 09d, parent: '%s').") % typeName % new_type.getId() % new_type.getIndex() % parentType.getName())) + + return new_type; +} + +av::Type +av::Type::createType(Type parentType, const std::string& typeName, + Create* create, bool isPublic) +{ + // check for duplicates + if (isTypeRegistered(typeName)) { + AVANGO_LOG(logger,logging::FATAL , boost::str(boost::format("createType(): duplicate type name '%1%' used. exiting!") % typeName)) + + ::abort(); + } + + // check if parent type exists + if (parentType != badType() && + parentType.getIndex() >= type_data_vec.size()) { + + AVANGO_LOG(logger,logging::WARN , boost::str(boost::format("createType(): parent '%1%' of '%2%' doesn't exist yet (parent idx: %3%, max idx: %4%), returning 'badType'") % parentType.getName() % typeName % parentType.getIndex() % type_data_vec.size())) + + return badType(); + } + + // ok, lets do it + Type new_type = allocateNewType(isPublic, true, false); + registerNewType(typeName, parentType, new_type, create); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("createType(): created type '%s' (id: % 09d, idx: % 09d, parent: '%s')") % typeName % new_type.getId() % new_type.getIndex() % parentType.getName())) + + return new_type; +} + +void +av::Type::setDistributable(bool isDistributable) +{ + type_data_vec[getIndex()].mDistributable = isDistributable; +} + +bool +av::Type::isDistributable() const +{ + return type_data_vec[getIndex()].mDistributable; +} + +bool +av::Type::isDerivedFrom(Type typeToCheck) const +{ + Type parent_type = getParent(); + + while (parent_type != badType()) { + if (typeToCheck == parent_type) { + return true; + } + parent_type = parent_type.getParent(); + } + return false; +} + +bool +av::Type::isOfType(Type typeToCheck) const +{ + return (*this == typeToCheck || isDerivedFrom(typeToCheck)); +} + +av::TypeList +av::Type::getAllDerivedFrom() const +{ + TypeList derived_types; + + for (unsigned int i = getIndex(); i < type_data_vec.size(); ++i) { + if (type_data_vec[i].mType.isDerivedFrom(*this)) { + derived_types.push_back(type_data_vec[i].mType); + } + } + return derived_types; +} + +av::Typed* +av::Type::createInstance() +{ + if (!canCreate()) { + return 0; + } + + av::Typed* obj = type_data_vec[getIndex()].mCreate->makeInstance(); + + AVANGO_LOG(logger,logging::DEBUG , boost::str(boost::format("createInstance(): created instance of type '%1%'") % type_data_vec[getIndex()].mName)) + + return obj; +} + +/* static */ av::Typed* +av::Type::createInstanceOfType(const std::string& typeName, + bool /*unloadable*/) +{ + Type type = getByName(typeName); + + if (type != badType()) + return type.createInstance(); + else + throw std::invalid_argument("invalid type: " + typeName); +} + +/* static */ void +av::Type::dumpTypeMap() +{ + AVANGO_LOG(logger,logging::INFO , boost::str(boost::format("dumpTypeMap(): dumping %1% types") % type_map.size())) + + size_t longest_name_size = 0; + + for (TypeMap::const_iterator current_type = type_map.begin(); + current_type != type_map.end(); ++current_type) { + const size_t name_size ((*current_type).first.size()); + + if (name_size > longest_name_size) { + longest_name_size = name_size; + } + } + + for (TypeMap::const_iterator current_type = type_map.begin(); + current_type != type_map.end(); ++current_type) { + const std::string name (current_type->first); + const int index (current_type->second); + const TypeData& current_type_data (type_data_vec[index]); + + std::string derivation; + + { + Type act_type = current_type_data.mType; + + while (!act_type.isBad()) { + derivation += act_type.getName(); + + act_type = act_type.getParent(); + + if (!act_type.isBad()) + derivation += "->"; + } + } + + std::string buffer(longest_name_size - name.size(), ' '); + + AVANGO_LOG(logger,logging::INFO , boost::str(boost::format("%1%'%2%' idx: %3% [derivation: %4%] [public: %5%] [distributable: %6%]") % buffer % name % index + % (!derivation.empty() ? derivation : "none") + % (current_type_data.mCreate ? "yes" : " no") + % (current_type_data.mDistributable ? "yes" : " no"))) + + buffer = std::string(longest_name_size + 17, ' '); + + } +} + +av::InputStream& av::operator>>(av::InputStream& is, av::Type& value) +{ + uint32_t id; + is >> id; + value = Type(id); + return is; +} + +av::OutputStream& av::operator<<(av::OutputStream& os, const av::Type& value) +{ + uint32_t id = value.getId(); + os << id; + return os; +} diff --git a/avango-core/src/avango/types/tests/TestContainerPool.cpp b/avango-core/src/avango/types/tests/TestContainerPool.cpp new file mode 100644 index 00000000..750013f1 --- /dev/null +++ b/avango-core/src/avango/types/tests/TestContainerPool.cpp @@ -0,0 +1,53 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include +#include + +#include + +namespace +{ + TEST(registerContainers) + { + av::BoolObject::initClass(); + av::Link obj1(new av::BoolObject); + av::FieldContainer::IDType obj1_id(obj1->getId()); + CHECK_EQUAL(obj1.getPtr(), av::ContainerPool::getContainerById(obj1_id)); + obj1.clear(); + CHECK_EQUAL(obj1.getPtr(), av::ContainerPool::getContainerById(obj1_id)); + } + +} // namespace + +int main() +{ + av::getRootLogger().addConsoleAppender(); + av::ApplicationInstance::get(); + return UnitTest::RunAllTests(); +} + diff --git a/avango-core/src/avango/types/tests/TestLibType.cpp b/avango-core/src/avango/types/tests/TestLibType.cpp new file mode 100644 index 00000000..129caa66 --- /dev/null +++ b/avango-core/src/avango/types/tests/TestLibType.cpp @@ -0,0 +1,48 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +// includes, system + +// includes, project + +#include +#include + +#include + +// variables, exported + +// functions, exported + +int main() +{ + av::getRootLogger().addConsoleAppender(); + + av::Type::init(); + + return UnitTest::RunAllTests(); +} diff --git a/avango-core/src/avango/types/tests/TestType.cpp b/avango-core/src/avango/types/tests/TestType.cpp new file mode 100644 index 00000000..570c4d6d --- /dev/null +++ b/avango-core/src/avango/types/tests/TestType.cpp @@ -0,0 +1,115 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// include i/f header + +// includes, system + +#include +#include + +// includes, project + +#include + +#include + +// variables, exported + +// internal unnamed namespace + +namespace +{ + + class CleanTypeSystemFixture { + public: + CleanTypeSystemFixture() { av::Type::init(); } + virtual ~CleanTypeSystemFixture() {} + }; + + TEST_FIXTURE(CleanTypeSystemFixture, checkBadType) + { + av::Type bad_type = av::Type::badType(); + CHECK_EQUAL(0U, bad_type.getId()); + CHECK_EQUAL("BAD_TYPE", bad_type.getName()); + } + + class HierarchyFixture : public CleanTypeSystemFixture { + public: + HierarchyFixture() + : mParent(av::Type::createAbstractType(av::Type::badType(), + "Parent", + true)), + mChild1(av::Type::createAbstractType( mParent, "Child1", true)), + mChild2(av::Type::createAbstractType( mParent, "Child2", true)) + {} + + protected: + av::Type mParent; + av::Type mChild1; + av::Type mChild2; + }; + + TEST_FIXTURE(HierarchyFixture, checkTypesValid) + { + CHECK(!mParent.isBad()); + CHECK(!mChild1.isBad()); + CHECK(!mChild2.isBad()); + } + + TEST_FIXTURE(HierarchyFixture, checkIsDerivedFrom) + { + CHECK(mChild1.isDerivedFrom(mParent)); + CHECK(mChild2.isDerivedFrom(mParent)); + CHECK(!mChild2.isDerivedFrom(mChild1)); + CHECK(!mChild2.isDerivedFrom(mChild2)); + CHECK(!mParent.isDerivedFrom(mChild1)); + } + + + TEST_FIXTURE(HierarchyFixture, checkIsOfType) + { + CHECK(mParent.isOfType(mParent)); + CHECK(mChild2.isOfType(mParent)); + CHECK(!mChild2.isOfType(mChild1)); + } + + TEST_FIXTURE(HierarchyFixture, checkAllDerived) + { + CHECK_EQUAL(2U, mParent.getAllDerivedFrom().size()); + } + + TEST_FIXTURE(HierarchyFixture, checkIds) + { + av::Type a(mParent); + av::Type b(mParent.getId()); + + CHECK_EQUAL(mParent.getId(), a.getId()); + CHECK_EQUAL(mParent, b); + } + +} // namespace + +// functions, exported diff --git a/avango-daemon/CMakeLists.txt b/avango-daemon/CMakeLists.txt new file mode 100644 index 00000000..a85ade75 --- /dev/null +++ b/avango-daemon/CMakeLists.txt @@ -0,0 +1,53 @@ +############################################################################### +# generate Config.h +############################################################################### +FILE(READ include/avango/daemon/Config.h.in AVANGO_CONFIG_IN) + +SET(AVANGO_CONFIG_OUT ${AVANGO_CONFIG_IN}) + +STRING(REGEX MATCHALL "%\\([^\\)]+\\)s" AVANGO_CONFIG_VARIABLES ${AVANGO_CONFIG_IN}) + +FOREACH(_CUR_VARIABLE ${AVANGO_CONFIG_VARIABLES}) + SET(_STRIPPED_VARIABLE "") + STRING(REGEX REPLACE "%\\(" "" _STRIPPED_VARIABLE ${_CUR_VARIABLE}) + STRING(REGEX REPLACE "\\)s" "" _STRIPPED_VARIABLE ${_STRIPPED_VARIABLE}) + STRING(REPLACE ${_CUR_VARIABLE} ${_STRIPPED_VARIABLE} AVANGO_CONFIG_OUT ${AVANGO_CONFIG_OUT}) +ENDFOREACH(_CUR_VARIABLE) + +FILE(WRITE include/avango/daemon/Config.h ${AVANGO_CONFIG_OUT}) + +############################################################################### +# determine source and header files +############################################################################### +file(GLOB AVANGO_DAEMON_SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + src/avango/daemon/*.cpp + src/avango/daemon/dtrack/*.cpp + src/avango/daemon/dtrack/*.h + include/avango/daemon/*.h +) + +IF (NOT DEFINE_AVANGO_DAEMON_VRPN_SUPPORT) + LIST(REMOVE_ITEM AVANGO_DAEMON_SRC "src/avango/daemon/VRPNClient.cpp") +ENDIF (NOT DEFINE_AVANGO_DAEMON_VRPN_SUPPORT) + +############################################################################### +# set link directories and link dependencies +############################################################################### +LINK_DIRECTORIES(${LIB_PATHS}) + +ADD_LIBRARY( avango_daemon SHARED + ${AVANGO_DAEMON_SRC} +) + +INCLUDE_DIRECTORIES( avango_daemon + ${INCLUDE_PATHS} + include + ../avango-core/include) + +ADD_DEPENDENCIES ( avango_daemon avango_core) + +IF (NOT ${LIBRARIES} STREQUAL "") + TARGET_LINK_LIBRARIES( avango_daemon debug ${LIBRARIES} optimized ${LIBRARIES}) +ENDIF (NOT ${LIBRARIES} STREQUAL "") + + diff --git a/avango-daemon/include/avango/daemon/Config.h b/avango-daemon/include/avango/daemon/Config.h new file mode 100644 index 00000000..f5260cfe --- /dev/null +++ b/avango-daemon/include/avango/daemon/Config.h @@ -0,0 +1,49 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_DAEMON_CONFIG_H) +#define AVANGO_DAEMON_CONFIG_H + +/** + * \file + * \ingroup av_daemon + */ + +#if AVANGO_DAEMON_DEBUG +#define AVANGO_DAEMON_DEBUG 1 +#else +#undef AVANGO_DAEMON_DEBUG +#endif + +#if AVANGO_DAEMON_VRPN_SUPPORT +#define VRPN_SUPPORT 1 +#else +#undef VRPN_SUPPORT +#endif + +#define AVANGO_DAEMON_VERSION_MAJOR AVANGO_DAEMON_VERSION_MAJOR +#define AVANGO_DAEMON_VERSION_MINOR AVANGO_DAEMON_VERSION_MINOR +#define AVANGO_DAEMON_VERSION_MAINT AVANGO_DAEMON_VERSION_MAINT + +#endif // #if !defined(AVANGO_DAEMON_CONFIG_H) + diff --git a/avango-daemon/include/avango/daemon/Config.h.in b/avango-daemon/include/avango/daemon/Config.h.in new file mode 100644 index 00000000..2abcc9a0 --- /dev/null +++ b/avango-daemon/include/avango/daemon/Config.h.in @@ -0,0 +1,49 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_DAEMON_CONFIG_H) +#define AVANGO_DAEMON_CONFIG_H + +/** + * \file + * \ingroup av_daemon + */ + +#if %(AVANGO_DAEMON_DEBUG)s +#define AVANGO_DAEMON_DEBUG 1 +#else +#undef AVANGO_DAEMON_DEBUG +#endif + +#if %(AVANGO_DAEMON_VRPN_SUPPORT)s +#define VRPN_SUPPORT 1 +#else +#undef VRPN_SUPPORT +#endif + +#define AVANGO_DAEMON_VERSION_MAJOR %(AVANGO_DAEMON_VERSION_MAJOR)s +#define AVANGO_DAEMON_VERSION_MINOR %(AVANGO_DAEMON_VERSION_MINOR)s +#define AVANGO_DAEMON_VERSION_MAINT %(AVANGO_DAEMON_VERSION_MAINT)s + +#endif // #if !defined(AVANGO_DAEMON_CONFIG_H) + diff --git a/avango-daemon/include/avango/daemon/DTrack.h b/avango-daemon/include/avango/daemon/DTrack.h new file mode 100644 index 00000000..d3a4af25 --- /dev/null +++ b/avango-daemon/include/avango/daemon/DTrack.h @@ -0,0 +1,101 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_DTRACK_H) +#define AV_DAEMON_DTRACK_H + +#include + +/** + * \file + * \ingroup av_daemon + */ + +/** + * Foreward declaration of the DTrack class declarated in dtrack.h + */ +class DTrack; + +namespace av +{ + namespace daemon + { + /** + * An Avango NG device for processing DTrack udp packets (ASCII protocol). + * (from A.R.T. GmbH) + * + * \ingroup av_daemon + */ + class DTrack : public Device + { + AV_BASE_DECLARE(); + + public: + /** + * Constructor + */ + DTrack(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~DTrack(); + + /** + * Inherited from base class, implements the initialization of this device. + */ + void startDevice(); + + /** + * Inherited from base class, implements the loop in which the device is read out. + */ + void readLoop(); + + /** + * Inherited from base class, implements the closing operation of this device. + */ + void stopDevice(); + + /** + * Inherited from base class, returns a list of settable features. + */ + const std::vector& queryFeatures(); + + private: + + ::boost::shared_ptr< ::DTrack> mDTrack; + ::std::vector< ::std::string> mRequiredFeatures; + size_t mPort; + size_t mTimeout; + + bool parseFeatures(); + unsigned long int convert_charpointer_to_ulong(const char* arg) const; + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/Device.h b/avango-daemon/include/avango/daemon/Device.h new file mode 100644 index 00000000..5fca88e2 --- /dev/null +++ b/avango-daemon/include/avango/daemon/Device.h @@ -0,0 +1,183 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_DEVICE_H) +#define AV_DAEMON_DEVICE_H + +#include +#include +#include +#include + +#if BOOST_VERSION > 104000 +#include +namespace av +{ +typedef ::boost::thread Thread; +} +#else +#include +namespace av +{ + typedef ::boost::thread Thread; +} +#endif + +/** + * \file + * \ingroup av_daemon + */ + +namespace av +{ + namespace daemon + { + /** + * Abstract base class of all devices. Devices are used by the DeviceDaemon to interface + * to external devices like tracking cameras or input devices. The DeviceDaemon communicates + * via shared memory with an Avango NG application. + * + * \ingroup av_daemon + */ + class Device : public Base + { + AV_BASE_DECLARE_ABSTRACT(); + + public: + + typedef std::map > NumStationMap; + typedef std::map > StringStringMap; + + /** + * Constructor. + */ + Device(); + + /** + * Add a station to this device identified by a station number. Stations are the basic + * entities which are communicated to interested processes via shared memory. + */ + virtual void addStation(int station_number, Station* station); + + /** + * Device specific parameters can be passed via this method in a generic way. The HIDInput + * device for example accepts the features 'tty', 'vendor' and 'product'. Features + * are evaluated on startup. + */ + virtual void configureFeature(const std::string& feature, const std::string& value); + + /** + * Removes the given feature from the feature map. + */ + virtual void unconfigureFeature(const std::string& feature); + + /** + * This function returns the value for a specific feature. If the requested feature has + * not previously been set, the empty string is returned. + */ + virtual std::string queryFeature(const std::string& feature); + + /** + * Returns the name of a station by a given ID, if not exists an empty string is returned. + */ + virtual std::string getStationName(int id); + + /** + * Starts up the device. First the features are queried and evaluated. Then a separate + * process is started using av_thread::create. This process updates the station data + * in an endless loop. + */ + bool startUp(); + + /** + * Shuts the device down. + */ + bool shutDown(); + + /** + * Returns true if the device is running. + */ + bool isDeviceRunning(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + ~Device(); + + /** + * This function is called once before the separate thread is created. It is + * supposed to be overloaded by derived classes. + */ + virtual void startDevice() = 0; + + /** + * This function is called once in the created thread. It is supposed to be + * overloaded by derived classes and should contain an endless loop reading + * device data and updating the the station records. + * The loop should look like this: while (mKeepRunning) { ... } + */ + virtual void readLoop() = 0; + + /** + * This function is called after the thread is terminated. It is + * supposed to be overloaded by derived classes. + */ + virtual void stopDevice() = 0; + + /** + * This function should return a list of all available features the can be set. + */ + virtual const std::vector& queryFeatures() = 0; + + /** + * A map of stations of this device. + */ + NumStationMap mStations; + + /** + * A map of features of this device. + */ + StringStringMap mFeatures; + + /** + * Variable used to trigger the loop + */ + bool mKeepRunning; + + private: + + static void threadFunction(Device* device); + + const std::string mEmptyFeature; + + ::boost::shared_ptr< av::Thread > mThread; + bool mRunning; + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/DeviceActuator.h b/avango-daemon/include/avango/daemon/DeviceActuator.h new file mode 100644 index 00000000..2d0320fc --- /dev/null +++ b/avango-daemon/include/avango/daemon/DeviceActuator.h @@ -0,0 +1,88 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_DEVICEACTUATOR_H) +#define AV_DAEMON_DEVICEACTUATOR_H + + +/** + * \file + * \ingroup av_daemon + */ + +#include + +#include +#include +#include + +namespace av +{ + namespace daemon + { + /** + * Communicates with DeviceService and provides shared data + * of a device the associated DeviceService is connected with. + * This class should be the base class for specific actuator + * implementations used to send commands or set states of a + * specific device. (An example can be found in WiimoteActuator.) + * + * \ingroup av_daemon + */ + class DeviceActuator : public FieldContainer + { + + AV_FC_DECLARE(); + + public: + + DeviceActuator(); + ~DeviceActuator(); + + /** + * Name of device service to communicate with. + */ + SFDeviceService DeviceService; + + /** + * Name of station to connect with. + */ + SFString Station; + + /** + * Inherited from av::FieldContainer. + */ + /* virtual */ void fieldHasChanged(const av::Field& field); + + protected: + + std::string mStation; + av::Link mService; + + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/DeviceDaemon.h b/avango-daemon/include/avango/daemon/DeviceDaemon.h new file mode 100644 index 00000000..0628b48f --- /dev/null +++ b/avango-daemon/include/avango/daemon/DeviceDaemon.h @@ -0,0 +1,88 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_DAEMON_DEVICEDAEMON_H) +#define AVANGO_DAEMON_DEVICEDAEMON_H + + + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include +#include + +namespace av +{ + namespace daemon + { + /** + * The DeviceDaemon main class, contains the main loop in which for all + * given devices a thread is created. + * + * \ingroup av_daemon + */ + class DeviceDaemon : public Base + { + AV_BASE_DECLARE(); + + public: + + /** + * Constructor. + */ + DeviceDaemon(); + + /** + * This method appends a device to the internal list of devices that + * will be started when run() is called. + */ + void appendDevice(av::daemon::Device* device); + + /** + * This method tries to start up all given devices and then enters + * the main loop until devices should be shut down. + */ + void run(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + ~DeviceDaemon(); + + private: + + std::vector > mDevices; + + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/DeviceSensor.h b/avango-daemon/include/avango/daemon/DeviceSensor.h new file mode 100644 index 00000000..2c05e799 --- /dev/null +++ b/avango-daemon/include/avango/daemon/DeviceSensor.h @@ -0,0 +1,241 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_DEVICESENSOR_H) +#define AV_DAEMON_DEVICESENSOR_H + + +/** + * \file + * \ingroup av_daemon + */ + +#include + +#include +#include +#include + +namespace av +{ + namespace daemon + { + /** + * Communicates with DeviceService and provides input data + * of the device the associated DeviceService is connected with. + * Depending on how the corresponding device is configured + * the data is provided via fields for Values, Buttons, LEDs and + * a Matrix. + * + * Note: A sensor can only be used to readout input data. Setting + * field values by hand will have no effect. To send commands + * to a device you should use an actuator. + * + * \ingroup av_daemon + */ + class DeviceSensor : public FieldContainer + { + + AV_FC_DECLARE(); + + public: + + DeviceSensor(); + virtual ~DeviceSensor(); + + /** + * Name of device service to communicate with. + */ + SFDeviceService DeviceService; + + /** + * Name of station to connect with. + */ + SFString Station; + + /** + * Reset station values to '0' after read. + */ + SFBool ResetValuesOnRead; + + /** + * Transformation matrix provided by given station (read-only). + */ + av::osg::SFMatrix Matrix; + + /** + * Read-only fields: Button states of connected station. + */ + SFBool Button0; + SFBool Button1; + SFBool Button2; + SFBool Button3; + SFBool Button4; + SFBool Button5; + SFBool Button6; + SFBool Button7; + SFBool Button8; + SFBool Button9; + SFBool Button10; + SFBool Button11; + SFBool Button12; + SFBool Button13; + SFBool Button14; + SFBool Button15; + SFBool Button16; + SFBool Button17; + SFBool Button18; + SFBool Button19; + SFBool Button20; + SFBool Button21; + SFBool Button22; + SFBool Button23; + SFBool Button24; + SFBool Button25; + SFBool Button26; + SFBool Button27; + SFBool Button28; + SFBool Button29; + SFBool Button30; + SFBool Button31; + + /** + * Read-only fields: Value states of connected station. + */ + SFFloat Value0; + SFFloat Value1; + SFFloat Value2; + SFFloat Value3; + SFFloat Value4; + SFFloat Value5; + SFFloat Value6; + SFFloat Value7; + SFFloat Value8; + SFFloat Value9; + SFFloat Value10; + SFFloat Value11; + SFFloat Value12; + SFFloat Value13; + SFFloat Value14; + SFFloat Value15; + + /** + * Read-only fields: LED states of connected station. + */ + SFBool LED0; + SFBool LED1; + SFBool LED2; + SFBool LED3; + SFBool LED4; + SFBool LED5; + SFBool LED6; + SFBool LED7; + SFBool LED8; + SFBool LED9; + SFBool LED10; + SFBool LED11; + SFBool LED12; + SFBool LED13; + SFBool LED14; + SFBool LED15; + + /** + * Tracker to world transformation. + */ + av::osg::SFMatrix TransmitterOffset; + + /** + * Sensor to device transformation. + */ + av::osg::SFMatrix ReceiverOffset; + + /** + * Device rotation (read-only). + */ + av::osg::SFQuat Rotation; + + /** + * Device translation (read-only). + */ + av::osg::SFVec3 Translation; + + /* virtual */ void evaluate(); + + private: + + /** + * Update matrix if changed. + */ + void updateMatrix(); + + /** + * Update button states if changed. + */ + void updateButtons(); + + /** + * Update value states if changed. + */ + void updateValues(); + + /** + * Update LED states if changed. + */ + void updateLEDs(); + + /** + * Readout Matrix provided by a specific device. + */ + void getMatrix(::osg::Matrixf&); + + /** + * Readout state of a specified Button provided by a specific device station. + */ + bool getButton(int b); + + /** + * Readout state of a specified LED provided by a specific device station. + */ + bool getLED(int l); + + /** + * Readout state of a specified Value provided by a specific device station. + */ + float getValue(int v); + + /** + * Set state of a specified LED. + */ + void setLED(int l, bool val); + + static const int sMaxButtons = 32; + static const int sMaxLEDs = 16; + static const int sMaxValues = 16; + + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/DeviceService.h b/avango-daemon/include/avango/daemon/DeviceService.h new file mode 100644 index 00000000..26b195ec --- /dev/null +++ b/avango-daemon/include/avango/daemon/DeviceService.h @@ -0,0 +1,142 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_DEVICESERVICE_H) +#define AV_DAEMON_DEVICESERVICE_H + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include + +/// @cond DOXYGEN_SHOULD_SKIP_THIS +namespace osg { + class Matrixf; +} +/// @endcond + +namespace av +{ + namespace daemon + { + + class Station; + class StationSegment; + + /** + * DeviceService, handles shared memory segment used to communicate with + * Avango Daemon instance. + * + * \ingroup av_daemon + */ + class DeviceService : public Base/*, public Singleton*/ + { + AV_BASE_DECLARE(); + + public: + + /** + * Public Constructor, to provide ability to construct own customized services. + */ + DeviceService(); + virtual ~DeviceService(); + + /** + * Connects to the shared memory segment. + */ + void connectDaemon(); + + /** + * Disconnects from the shared memory segment. + */ + void disconnectDaemon(); + + /** + * Get matrix of a specified station. + */ + const ::osg::Matrixf& getMatrix(const char* station); + + /** + * Get button state by specified station and number. + */ + int getButton(const char* station, int which); + + /** + * Get value state by specified station and number. + */ + float getValue(const char* station, int which); + + /** + * Get LED state by specified station and number. + */ + bool getLED(const char* station, int which); + + /** + * Set matrix of a specified station. + */ + void setMatrix(const char* station, const ::osg::Matrixf& value); + + /** + * Set a specific button of a specific station. + */ + void setButton(const char* station, int which, bool value); + + /** + * Set a specfic value of a specific station. + */ + void setValue(const char* station, int which, float value); + + /** + * Set LED state of a specific station. + */ + void setLED(const char* station, int which, bool value); + + bool getMatrixUsed(const char* station); + int getButtonsUsed(const char* station); + int getValuesUsed(const char* station); + int getLEDsUsed(const char* station); + + protected: + + const ::osg::Matrixf* mIdentityMatrix; + const char* mCachedStationName; + Station* mCachedStation; + StationSegment* mStationSegment; + + Station* lookupCachedStation(const char* name); + void clearStationCache(); + }; + + typedef SingleField > SFDeviceService; + typedef MultiField > MFDeviceService; + typedef Singleton DevService; + } + +} + +#endif // #if !defined(AV_DAEMON_DEVICESERVICE_H) diff --git a/avango-daemon/include/avango/daemon/Doxygen.h b/avango-daemon/include/avango/daemon/Doxygen.h new file mode 100644 index 00000000..6fe0a8a7 --- /dev/null +++ b/avango-daemon/include/avango/daemon/Doxygen.h @@ -0,0 +1,44 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_DAEMON_DOXYGEN_H) +#define AVANGO_DAEMON_DOXYGEN_H + +/** + * \defgroup av_daemon AVANGO Daemon Library + */ + +/** + * \file + * \ingroup av_daemon + */ + +/** + * \namespace av::daemon + * Avango DAEMON Library + * + * \ingroup av_daemon + */ + +#endif // #if !defined(AVANGO_DAEMON_DOXYGEN_H) + diff --git a/avango-daemon/include/avango/daemon/HIDInput.h b/avango-daemon/include/avango/daemon/HIDInput.h new file mode 100644 index 00000000..e76446f2 --- /dev/null +++ b/avango-daemon/include/avango/daemon/HIDInput.h @@ -0,0 +1,250 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_HIDINPUT_H) +#define AV_DAEMON_HIDINPUT_H + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include +#include +#include +#include + +#include + +namespace av +{ + namespace daemon + { + /** + * An Avango NG device to communicate with any devices that are registered + * via Linux event system (i.e. /dev/input/something using linux/input.h) such as + * mice, keyboards, joysticks and gamepads. + * + * \ingroup av_daemon + */ + class HIDInput : public Device + { + + AV_BASE_DECLARE(); + + public: + + typedef std::map > HIDMapping; + typedef std::map > HIDLEDMapping; + typedef std::map > StationHIDMappingLookup; + typedef std::map > StationHIDLEDMappingLookup; + typedef std::map > LastLEDStateLookup; + + /** + * Constructor + */ + HIDInput(); + + /** + * Overrides addStation of av::daemon::Device + */ + virtual void addStation(int station_number, Station* station); + + /** + * Overrides configureFeature of av::daemon::Device + */ + virtual void configureFeature(const std::string& feature, const std::string& value); + + /** + * Overrides queryFeature of av::daemon::Device + */ + virtual std::string queryFeature(const std::string& feature); + + /** + * Returns the name of the first station as string. Used for the Python binding. + */ + virtual std::string getFirstStation(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~HIDInput(); + + /** + * Inherited from interface av::daemon::Device, used to initialize the device. + */ + void startDevice(); + + /** + * Inherited from interface av::daemon::Device, used to read out events. + */ + void readLoop(); + + /** + * Inherited from interface av::daemon::Device, used to stop device. + */ + void stopDevice(); + + /** + * Inherited from interface av::daemon::Device, returns a list of settable features. + */ + const std::vector& queryFeatures(); + + /** + * Open device. + */ + bool open(); + + /** + * Returns true if device is open. + */ + bool isOpen() const; + + /** + * Close device. + */ + bool close(); + + /** + * Read input event. + */ + bool readEvent(struct input_event* event); + + /** + * Write event. + */ + bool writeEvent(const struct input_event& event); + + /** + * Processes a mapping request. Maps Linux events (e.g. EV_REL::REL_X) to a + * specific field (e.g. Value0) of the registered station. + */ + void processMappingRequest(const std::string& feature,const std::string& value); + + /** + * Convenience method for debug printing. + */ + void printHIDMapping(const HIDMapping& hidmapping) const; + + /** + * Packs two ushorts into one uint. + */ + unsigned int pack_into_uint(unsigned short v1,unsigned short v2) const; + + /** + * Unpacks one uint into two ushorts. + */ + void unpack_from_uint(unsigned int v,unsigned short& v1,unsigned short& v2) const; + + /** + * Converts a char* to unsigned long. + */ + unsigned long int convert_charpointer_to_ulong(const char* arg) const; + + /** + * Convenience method for debug printing. + */ + void printMaps() const; + + /** + * Convenience method for debug printing. + */ + void printAbsInfo() const; + + /** + * Convenience method for debug printing. + */ + void printStatus() const; + + std::string eventPairToString(unsigned short eventType,unsigned short eventCode) const; + std::string stationPairToString(unsigned short eventType,unsigned short eventCode) const; + + /** + * Before the device is started this method ensures that the required and + * optional features are set properly. In case of an error the device will + * not start. + */ + int parse_features(); + + void retrieve_abs_info(); + + virtual void updateLED(unsigned short eventCode, bool on); + virtual void updateLEDs(bool force = false); + virtual void startLEDs(); + virtual void stopLEDs(); + + // For every EV_ABS type we store the values (current, min, max, flat, fuzz) + typedef std::map > AbsInfoMap; + + HIDMapping mDefaultHIDMapping; + HIDLEDMapping mDefaultHIDLEDMapping; + StationHIDMappingLookup mStationHIDMappingLookup; + StationHIDLEDMappingLookup mStationHIDLEDMappingLookup; + LastLEDStateLookup mLastLEDStateLookup; + AbsInfoMap mAbsInfoMap; + std::vector mFeatures; + + int mFd; + std::string mTty; + bool mNormAbs; // normalize absolute values of EV_ABS in range [-1,1] + bool mAccumRel; // if set, ALL(!) REL events are accumulated in the requested station + // value! + int mResetRelCycle; // if >=0 reset EV_REL mapping to 0.0 if !_accumRel any _resetRel + // cycles where no new data was read + int mTimeout; // event timeout in milliseconds (default: 200) + + virtual float normalizeAbsValue(const struct input_event& event) const; + + bool stationLooksForEvent(int station_index, const struct input_event& event) const; + + void applyEventToStation(int station_index, const struct input_event& event); + + void clearRelativeStationValues(); + + template ValueType scanForOptionalFeature(const std::string& feature, ValueType default_value); + + + private: + +// bool stationLooksForEvent(int station_index, const struct input_event& event) const; + const HIDMapping& getStationHIDMapping(int station_index) const; + const HIDLEDMapping& getStationHIDLEDMapping(int station_index) const; + + bool scanUnsignedInteger(const std::string& int_string, unsigned int& return_value) const; + bool scanInteger(const std::string& int_string, int& return_value) const; + + template ValueType scanForRequiredFeature(const std::string& feature); + +// void applyEventToStation(int station_index, const struct input_event& event); +// void clearRelativeStationValues(); + + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/Init.h b/avango-daemon/include/avango/daemon/Init.h new file mode 100644 index 00000000..620f07ff --- /dev/null +++ b/avango-daemon/include/avango/daemon/Init.h @@ -0,0 +1,53 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_DAEMON_INIT_H) +#define AVANGO_DAEMON_INIT_H + +/** + * \file + * \ingroup av_daemon + */ + +#include + +namespace av +{ + namespace daemon + { + /** + * Initializes the Avango Daemon library. + * Usage: \code av::daemon:Init::initClass(); \endcode + * + * \ingroup av_daemon + */ + class Init + { + AV_TYPED_DECLARE_ABSTRACT(); + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/LinuxEvent.h b/avango-daemon/include/avango/daemon/LinuxEvent.h new file mode 100644 index 00000000..e8c474a4 --- /dev/null +++ b/avango-daemon/include/avango/daemon/LinuxEvent.h @@ -0,0 +1,63 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_LINUXEVENT_H) +#define AV_DAEMON_LINUXEVENT_H + +#include +#include + +/** + * \file + * \ingroup av_daemon + */ + +namespace av +{ + namespace daemon + { + /** + * Convenience class for converting a linux event type, given as string, + * into the corresponding event code. (see /usr/include/linux/input.h). + * + * \ingroup av_daemon + */ + class LinuxEvent : public ::std::map + { + public: + /** + * Returns the event code of a given event type. (e.g. "KEY_DOWN" = 108). + */ + static unsigned long getEventCode(const std::string& eventType); + /** + * Constructor + */ + LinuxEvent(); + + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/SharedMemorySegment.h b/avango-daemon/include/avango/daemon/SharedMemorySegment.h new file mode 100644 index 00000000..60e6c3bc --- /dev/null +++ b/avango-daemon/include/avango/daemon/SharedMemorySegment.h @@ -0,0 +1,90 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + + +#if !defined(AVANGO_DAEMON_SHAREDMEMORYSEGMENT_H) +#define AVANGO_DAEMON_SHAREDMEMORYSEGMENT_H + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include + + +namespace av +{ + namespace daemon + { + + /** + * Represents a shared memory segment. + * + * \ingroup av_daemon + */ + class SharedMemorySegment : private boost::noncopyable { + + public: + + /** + * Constructor. + */ + SharedMemorySegment(int /* key */, int /* size */); + + /** + * Destructor. + */ + ~SharedMemorySegment(); + + /** + * Create segment. + */ + void* segment() const; + + /** + * Returns size of segment. + */ + size_t size() const; + + /** + * Returns true if segment was created. + */ + bool created() const; + + private: + + bool mCreated; + int mSegmentKey; + int mSegmentId; + void* mSegment; + size_t mSegmentSize; + + }; + } +} + +#endif // #if !defined(AVANGO_DAEMON_SHAREDMEMORYSEGMENT_H) diff --git a/avango-daemon/include/avango/daemon/Station.h b/avango-daemon/include/avango/daemon/Station.h new file mode 100644 index 00000000..5d7f5c48 --- /dev/null +++ b/avango-daemon/include/avango/daemon/Station.h @@ -0,0 +1,124 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_STATION_H) +#define AV_DAEMON_STATION_H + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include +#include + + +namespace av +{ + namespace daemon + { + /** + * Class representing a station of Avango NG daemon. + * + * \ingroup av_daemon + */ + class Station : public Base { + + AV_BASE_DECLARE(); + + public: + + /** + * Constructor + */ + Station(); + + /** + * Destructor + */ + virtual ~Station(); + + public: + + const char* getName() const; + const ::osg::Matrixf& getMatrix() const; + + int getButton(int which) const; + const ::std::vector getButtons() const; + + float getValue(int which) const; + const ::std::vector getValues() const; + + bool getLED(int which) const; + const ::std::vector getLEDs() const; + + void setName(const char* name); + void setMatrix(const ::osg::Matrixf& matrix); + void setButton(int which, int on); + void setValue(int which, float val); + void setLED(int which, bool on); + void setUsage(bool matrix = 0, int buttons = 0, int values = 0, int leds = 0); + + bool getMatrixUsed() const; + int getButtonsUsed() const; + int getValuesUsed() const; + int getLEDsUsed() const; + + static const int sMaxNameLength = 128; + static const int sMaxButtons = 32; + static const int sMaxValues = 256; + static const int sMaxLeds = 16; + + private: + + // retain static memory layout since it gets put into a shared + // memory segment not autogrowable! + char mName[sMaxNameLength]; + ::osg::Matrixf mMatrix; // this should work since fpMatrix has the same memory layout float[4][4] + int mButton[sMaxButtons]; + float mValue[sMaxValues]; + bool mLed[sMaxLeds]; + bool mMatrixUsed; + int mButtonsUsed; + int mValuesUsed; + int mLedsUsed; + + /** + * Made private to prevent copying construction. + */ + Station(const Station&); + + /** + * Made private to prevent assignment. + */ + const Station& operator=(const Station&); + + }; + } +} + + +#endif // #if !defined(AV_OSG_STATION_H) diff --git a/avango-daemon/include/avango/daemon/StationBlock.h b/avango-daemon/include/avango/daemon/StationBlock.h new file mode 100644 index 00000000..19a63cc0 --- /dev/null +++ b/avango-daemon/include/avango/daemon/StationBlock.h @@ -0,0 +1,99 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + + +#if !defined(AV_DAEMON_STATIONBLOCK_H) +#define AV_DAEMON_STATIONBLOCK_H + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include + + +namespace av +{ + namespace daemon + { + /** + * Helper class for getting a station from av-daemon (used by av::daemon::StationSegment). + * + * \ingroup av_daemon + */ + class StationBlock { + + public: + + /** + * Constructor + */ + StationBlock(); + + /** + * Get a station by given name. + */ + Station* getStation(const char* name); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~StationBlock(); + + private: + + /** + * Builtin declaration here; definition is in impl. unit w/o value! + * needed because of the array size for mStations!!! + */ + static const int sMaxStationNum = 64; + + /** + * Retain static memory layout since it gets put into a shared + * memory segment not autogrowable! + */ + Station mStations[sMaxStationNum]; + int mNumStations; + boost::mutex mMutex; + + /** + * Made private to prevent copying construction. + */ + StationBlock(const StationBlock&); + + /** + * Made private to prevent assignment. + */ + const StationBlock& operator=(const StationBlock&); + + }; + } +} + +#endif // #if !defined(AV_DAEMON_STATIONBLOCK_H) diff --git a/avango-daemon/include/avango/daemon/StationSegment.h b/avango-daemon/include/avango/daemon/StationSegment.h new file mode 100644 index 00000000..0c130bc7 --- /dev/null +++ b/avango-daemon/include/avango/daemon/StationSegment.h @@ -0,0 +1,88 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_STATIONSEGMENT_H) +#define AV_DAEMON_STATIONSEGMENT_H + +/** + * \file + * \ingroup av_daemon + */ + +#include + + +namespace av +{ + namespace daemon + { + class Station; + class StationBlock; + class SharedMemorySegment; + + /** + * Class for handling a shared memory segment. + * + * \ingroup av_daemon + */ + class StationSegment { + + + public: + + StationSegment(); + virtual ~StationSegment(); + + /** + * Returns station of given name. + */ + Station* getStation(const char*); + + /** + * Returns station of given name. + */ + Station* getStation(const ::std::string&); + + + private: + + /** + * Made private to prevent copying construction. + */ + StationSegment(const StationSegment&); + + /** + * Made private to prevent assignment. + */ + const StationSegment& operator=(const StationSegment&); + + SharedMemorySegment* mSharedMem; + StationBlock* mStationBlock; + + }; + } +} + +#endif // #if !defined(AV_OSG_STATIONSEGMENT_H) diff --git a/avango-daemon/include/avango/daemon/VRPNClient.h b/avango-daemon/include/avango/daemon/VRPNClient.h new file mode 100644 index 00000000..2e6d5911 --- /dev/null +++ b/avango-daemon/include/avango/daemon/VRPNClient.h @@ -0,0 +1,125 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + + +#if !defined(AV_DAEMON_VRPNCLIENT_H) +#define AV_DAEMON_VRPNCLIENT_H + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include +#include +#include + +#include + +namespace av +{ + namespace daemon + { + /** + * An Avango NG device for processing packets sent by a VRPN server. + * + * \ingroup av_daemon + */ + class VRPNClient : public Device + { + AV_BASE_DECLARE(); + + public: + /** + * Constructor + */ + VRPNClient(); + + /* + * Callback handler for analog devices, such as joysticks. + */ + void handleAnalog(const vrpn_ANALOGCB a); + + /* + * Callback handler for button devices. + */ + void handleButton(const vrpn_BUTTONCB b); + + /** + * Callback handler for tracking data (positions, orientations, accelerations, etc.) + */ + void handleTracker(const vrpn_TRACKERCB t); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~VRPNClient(); + + /** + * Inherited from base class, implements the initialization of this device. + */ + void startDevice(); + + /** + * Inherited from base class, implements the main loop for processing data. + */ + void readLoop(); + + /** + * Inherited from base class, implements the closing operation of this device. + */ + void stopDevice(); + + /** + * Inherited from base class, returns a list of settable features. + */ + const std::vector& queryFeatures(); + + /** + * Before the device is started this method ensures that the required and + * optional features are set properly. In case of an error the device will + * not start. + */ + bool parseFeatures(); + + private: + + std::string mVRPNServer; + std::vector mRequiredFeatures; + bool mStopped; + + vrpn_Analog_Remote* mVRPNAnalog; + vrpn_Button_Remote* mVRPNButton; + vrpn_Tracker_Remote* mVRPNTracker; + }; + } +} + +#endif + + diff --git a/avango-daemon/include/avango/daemon/WacomTablet.h b/avango-daemon/include/avango/daemon/WacomTablet.h new file mode 100644 index 00000000..6542e44b --- /dev/null +++ b/avango-daemon/include/avango/daemon/WacomTablet.h @@ -0,0 +1,101 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_WACOMTABLET_H) +#define AV_DAEMON_WACOMTABLET_H + +/** + * \file + * \ingroup av_daemon + */ + +#include +#include +#include +#include +#include + +namespace av +{ + namespace daemon + { + /** + * An Avango NG device for communication with a Wacom tablet. + * the Linux event system will propagate the inputs via /dev/input/wacom. + */ + class WacomTablet : public HIDInput + { + AV_BASE_DECLARE(); + + public: + /** + * Constructor + */ + WacomTablet(); + + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~WacomTablet(); + + /** + * Inherited from interface av::daemon::Device, used to initialize the device. + */ + void startDevice(); + + /** + * overrides readloop() from av::daemon::HIDInput, used to create a transformation Matrix + * from pen input + */ + void readLoop(); + + /** + * overrides normalizeAbsValue from HIDInput, used to perform custom normalization + * of some values + */ + float normalizeAbsValue(const input_event& event) const; + + /** + * Retrieves aspect ratio of tablet from maximum absolute values, Ratio is written in Value12 + */ + void retrieveAspectRatio(); + + /** + * overrides HIDInput::parse_features() to add toggle_reset property + */ + int parse_features(); + + /** + * toggle switch to reset absolute axes when pen is lifted up to zero + */ + bool mToggleReset; + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/Wiimote.h b/avango-daemon/include/avango/daemon/Wiimote.h new file mode 100644 index 00000000..94c57d28 --- /dev/null +++ b/avango-daemon/include/avango/daemon/Wiimote.h @@ -0,0 +1,84 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_WIIMOTE_H) +#define AV_DAEMON_WIIMOTE_H + +/** + * \file + * \ingroup av_daemon + */ + +#include + +namespace av +{ + namespace daemon + { + /** + * An Avango NG device for communication with a Nintendo Wiimote control. + * To use this device it is necessary to install the cwiid library. + * (http://abstrakraft.org/cwiid/ under GPL license) + * with patches #34 #35 and #36 (see tickets under cwiid webhome). + * In conjunction with a running wminput daemon started like this: + * "wminput [ma:ca:dd:re:ss:01] &" + * the Linux event system will propagate the inputs via /dev/input/. + */ + class Wiimote : public HIDInput + { + AV_BASE_DECLARE(); + + public: + /** + * Constructor + */ + Wiimote(); + + protected: + + /** + * Destructor made protected to prevent allocation on stack. + */ + virtual ~Wiimote(); + + /** + * Inherited from interface av::daemon::Device, used to initialize the device. + */ + void startDevice(); + + /** + * Implements updating LEDs. + */ + void updateLED(unsigned short eventCode, bool on); + + /** + * Implements stopping LEDs. + */ + void stopLEDs(); + }; + } +} + +#endif diff --git a/avango-daemon/include/avango/daemon/WiimoteActuator.h b/avango-daemon/include/avango/daemon/WiimoteActuator.h new file mode 100644 index 00000000..7631027e --- /dev/null +++ b/avango-daemon/include/avango/daemon/WiimoteActuator.h @@ -0,0 +1,87 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AV_DAEMON_WIIMOTEACTUATOR_H) +#define AV_DAEMON_WIIMOTEACTUATOR_H + + +/** + * \file + * \ingroup av_daemon + */ + +#include + +namespace av +{ + namespace daemon + { + /** + * Inherited from av::daemon::DeviceActuator. Immplements a + * concrete actuator to set LED states and different Rumble modes + * of an associated Nintendo Wiimote. + * + * \ingroup av_daemon + */ + class WiimoteActuator : public DeviceActuator + { + + AV_FC_DECLARE(); + + public: + + WiimoteActuator(); + ~WiimoteActuator(); + + /** + * Set LEDs of the connected Wiimote. + */ + SFBool LED0; + SFBool LED1; + SFBool LED2; + SFBool LED3; + + /** + * Set Rumble mode of the connected Wiimote. + */ + SFBool Rumble0; + SFBool Rumble1; + SFBool Rumble2; + SFBool Rumble3; + SFBool Rumble4; + SFBool Rumble5; + SFBool Rumble6; + + /** + * Resets the state of all LEDs and Rumble modes to their initial values. + */ + void reset(); + + /* virtual */ void evaluate(); + }; + } +} + +#endif diff --git a/avango-daemon/python/__init__.py b/avango-daemon/python/__init__.py new file mode 100644 index 00000000..a36f9eea --- /dev/null +++ b/avango-daemon/python/__init__.py @@ -0,0 +1,216 @@ +# -*- Mode:Python -*- + +########################################################################## +# # +# This file is part of AVANGO. # +# # +# Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der # +# angewandten Forschung (FhG), Munich, Germany. # +# # +# AVANGO is free software: you can redistribute it and/or modify # +# it under the terms of the GNU Lesser General Public License as # +# published by the Free Software Foundation, version 3. # +# # +# AVANGO is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU Lesser General Public # +# License along with AVANGO. If not, see . # +# # +########################################################################## + +''' +AvangoDaemon NG +=============== + +The AvangoDaemon is an independent instance for communication with +a variety of devices that serve as input data for Avango NG applications. +The AvangoDaemon has its own main loop in which for each device a thread +is running. Therefore the devices are decoupled from the Avango NG +main loop. Via shared memory segment the Avango NG application +exchanges data with the device instances. + +On Avango NG application side a DeviceSensor is used to read out data +coming from an appropriate input device. Whereas a DeviceActuator +can be used to send specific commands to the device, for example +see WiimoteActuator to set LEDs or Rumble modes on a connected +Nintendo Wiimote. + +On AvangoDaemon side implementations for different devices exist. +Examples are: + +HIDInput + To communicate with USB devices via standardized input interface + (such as keyboard, mouse and gamepads). + +Wiimote + A specific HIDInput to use a Nintendo Wiimote device. + Note: This device has a dependency to a patched version of 'wminput'. + (http://abstrakraft.org/cwiid with patches #34,#35 and #36) + +DTrack + For processing DTrack udp packets (ASCII protocol). + +WacomTablet + To communicate with a Wacom tablet. + +VRPNClient + A VRPN client consisting of vrpn_Tracker, vrpn_Button and vrpn_Analog devices. + Note: This device is linked to the vrpn library. + (http://www.cs.unc.edu/Research/vrpn) + + +Examples +======== + +There are some basic examples within your Avango NG installation, +that show the configuration and usage of these input devices. +''' + +from _daemon import * +from _daemon import _Device +from _daemon import _HIDHelper +from _daemon import _WacomTabletHelper +from _daemon import _WiimoteHelper +from _daemon import _DTrackHelper + +import avango.nodefactory +nodes = avango.nodefactory.NodeFactory('av::daemon::') + +class Station(object): + """Just a plain object to create an Avango station based on its (unique) name. + (properties: name). Station objects with the same name will refer to the same + Avango station.""" + def __init__(self, name): + self.name = name + +class _DeviceMixIn(object): + """A helper mix-in class that provides some advanced properties that can be set via [] + operator. In conjunction with the appropriate _DeviceHelper class a concrete device + class can be constructed.""" + def __init__(self): + super(_DeviceMixIn, self).__init__() + self._station = None + self._values = {} + self._buttons = {} + self._leds = {} + + def get_station(self): + return self._station + + def set_station(self, st): + self._station = st + self.add_station(0, st.name) + + class ValueProxy(object): + """Proxy object to override the functions that are called on access of list + values via [] operator.""" + def __init__(self, hid): + self._hid = hid + def __getitem__(self, key): + if self._hid._values.has_key(key): + return self._hid._values[key] + else : return '' + def __setitem__(self, key, value): + self._hid._values[key] = value + return self._hid.map_to_station_value(key, value) + + class ButtonProxy(object): + """Proxy object to override the functions that are called on access of list + values via [] operator.""" + def __init__(self, hid): + self._hid = hid + def __getitem__(self, key): + if self._hid._buttons.has_key(key): + return self._hid._buttons[key] + else : return '' + def __setitem__(self, key, value): + self._hid._buttons[key] = value + return self._hid.map_to_station_button(key, value) + + class LEDProxy(object): + """Proxy object to override the functions that are called on access of list + values via [] operator.""" + def __init__(self, hid): + self._hid = hid + def __getitem__(self, key): + if self._hid._leds.has_key(key): + return self._hid._leds[key] + else : return '' + def __setitem__(self, key, value): + self._hid._leds[key] = value + return self._hid.map_to_station_led(key, value) + + station = property(get_station, set_station) + buttons = property(ButtonProxy) + values = property(ValueProxy) + leds = property(LEDProxy) + +class HIDInput(_DeviceMixIn, _HIDHelper): + """Communicates with a device which is registered via Linux event system + such as a mouse, keyboard, joystick or a gamepad. Required properties: station, device, + value, button, led. Map incoming events like this: mydev.value[0] = \'EV_REL::REL_X\'. + Optional properties: norm_abs, accum_rel_events, reset_rel_values_cycle, timeout.""" + def __init__(self): + super(HIDInput, self).__init__() + +class WacomTablet(_DeviceMixIn, _WacomTabletHelper): + """Communicates with a Wacom tablet device which is registered via Linux event + system. Required properties: station, device. Map incoming events like this: + mydev.value[0] = \'EV_REL::REL_X\'. All appearing value und button events of a tablet + are already set up in the constructor of this class. Optional properties: value, button, + led, norm_abs, accum_rel_events, reset_rel_values_cycle, timeout, toggle_reset.""" + def __init__(self): + super(WacomTablet, self).__init__() + +class Wiimote(_DeviceMixIn, _WiimoteHelper): + """Communicates with a Nintendo Wiimote device which is registered via Linux event + system. Required properties: station, device, button, value. Map incoming events like + this: mydev.value[0] = \'EV_REL::REL_X\'. All appearing LED and Rumble events of a + Wiimote are already set up in the constructor of this class. Optional properties: + led, norm_abs, accum_rel_events, reset_rel_values_cycle, timeout.""" + def __init__(self): + super(Wiimote, self).__init__() + +class DTrack(_DTrackHelper): + """Avango NG device for processing DTrack udp packets (ASCII protocol). + Required properties: stations, port.""" + def __init__(self): + super(DTrack, self).__init__() + self._stations = {} + + class StationProxy(object): + """Proxy object to override the functions that are called on access of list + values via [] operator.""" + def __init__(self, dtrack): + self._dtrack = dtrack + def __getitem__(self, key): + if self._dtrack._stations.has_key(key): + return self._dtrack._stations[key] + else: return '' + def __setitem__(self, key, st): + self._dtrack._stations[key] = st + return self._dtrack.add_station(key, st.name) + + stations = property(StationProxy) + +if does_type_exist("av::daemon::VRPNClient"): + from _daemon import _VRPNClientHelper + + class VRPNClient(_VRPNClientHelper): + """Avango NG device for processing data sent by a VRPN server. This + client consists of vrpn_Tracker, vrpn_Button and vrpn_Analog devices.""" + def __init__(self): + super(VRPNClient, self).__init__() + self._station = None + + def get_station(self): + return self._station + + def set_station(self, st): + self._station = st + self.add_station(0, st.name) + + station = property(get_station, set_station) diff --git a/avango-daemon/python/_daemon.cpp b/avango-daemon/python/_daemon.cpp new file mode 100644 index 00000000..48524591 --- /dev/null +++ b/avango-daemon/python/_daemon.cpp @@ -0,0 +1,228 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef VRPN_SUPPORT +#include +#endif + +using namespace boost::python; +using namespace av::python; + +namespace boost +{ + namespace python + { + template struct pointee > + { + typedef T type; + }; + } +} + +namespace +{ + boost::shared_ptr mStationSegment(new av::daemon::StationSegment()); + + bool + doesTypeExist(std::string name) + { + return (av::Type::getByName(name) != av::Type::badType())? true : false; + } + + void + addStation(av::daemon::Device* self, int number, std::string name) + { + if (!mStationSegment) + throw std::runtime_error("No StationSegment available."); + + self->addStation(number, mStationSegment->getStation(name)); + } + + // wrapper for specialized queryFeature calls, required by .add_property + // (a better solution would be to use boost::bind, but unfortunately + // combining boost::bind with boost::python doesn't work in this case) + std::string getTTYFeature(av::daemon::Device* self) { return self->queryFeature("tty"); } + std::string getNormAbsFeature(av::daemon::Device* self) { return self->queryFeature("norm-abs"); } + std::string getAccumRelFeature(av::daemon::Device* self) { return self->queryFeature("accum-rel-events"); } + std::string getResetRelCycleFeature(av::daemon::Device* self) { return self->queryFeature("reset-rel-values-cycle"); } + std::string getTimeoutFeature(av::daemon::Device* self) { return self->queryFeature("timeout"); } + std::string getPortFeature(av::daemon::Device* self) { return self->queryFeature("port"); } + std::string getToggleResetFeature(av::daemon::Device* self) { return self->queryFeature("toggle-reset"); } + std::string getServerFeature(av::daemon::Device* self) { return self->queryFeature("server"); } + + // wrapper for specialized configureFeature calls, required by .add_property + std::string parseBoolString(std::string value) + { + if ((value == "true")||(value=="TRUE")||(value=="True")) return "1"; + if ((value == "false")||(value=="FALSE")||(value=="False")) return "0"; + return value; + } + void setTTYFeature(av::daemon::Device* self, std::string value) { self->configureFeature("tty", value); } + void setNormAbsFeature(av::daemon::Device* self, std::string value) { self->configureFeature("norm-abs",parseBoolString(value)); } + //void setNormAbsFeature(av::daemon::Device* self, bool value) { (value)?self->configureFeature("norm-abs", "1"):self->configureFeature("norm-abs", "0"); } + void setAccumRelFeature(av::daemon::Device* self, std::string value) { self->configureFeature("accum-rel-events", parseBoolString(value)); } + void setResetRelCycleFeature(av::daemon::Device* self, std::string value) { self->configureFeature("reset-rel-values-cycle", value); } + void setTimeoutFeature(av::daemon::Device* self, std::string value) { self->configureFeature("timeout", value); } + void setPortFeature(av::daemon::Device* self, std::string value) { self->configureFeature("port", value); } + void setToggleResetFeature(av::daemon::Device* self, std::string value) { self->configureFeature("toggle-reset", parseBoolString(value)); } + void setServerFeature(av::daemon::Device* self, std::string value) { self->configureFeature("server", value); } + + // set LED states + void setLED(av::daemon::HIDInput* self, int number, int value) + { + mStationSegment->getStation(self->getFirstStation())->setLED(number,value); + } + void setAllLEDs(av::daemon::HIDInput* self, int value) + { + av::daemon::Station* st = mStationSegment->getStation(self->getFirstStation()); + for (int i=0; isetLED(i, value); + } + + // wrapper for mappings + void + mapToStationButton(av::daemon::HIDInput* self, int number, std::string event) + { + std::string feature = self->getFirstStation() + "::STATION_BUTTON::" + boost::lexical_cast(number); + self->configureFeature(feature, event); + } + void + mapToStationValue(av::daemon::HIDInput* self, int number, std::string event) + { + std::string feature = self->getFirstStation() + "::STATION_VALUE::" + boost::lexical_cast(number); + self->configureFeature(feature, event); + } + void + mapToStationLED(av::daemon::HIDInput* self, int number, std::string event) + { + std::string feature = self->getFirstStation() + "::STATION_LED::" + boost::lexical_cast(number); + self->configureFeature(feature, event); + } + + void + run(object devices) + { + av::Link daemon(new av::daemon::DeviceDaemon()); + if(!daemon.isValid()) + throw std::runtime_error("No instance of a DeviceDaemon available."); + + for (int i = 0; i != extract(devices.attr("__len__")()); ++i) + { + daemon->appendDevice(extract(devices[i])); + } + + daemon->run(); + } +} + +BOOST_PYTHON_MODULE(_daemon) +{ + // initialize Avango Daemon + av::daemon::Init::initClass(); + + // Avango NG application instances + class_, bases, boost::noncopyable >("DeviceSensor", "docstring", no_init); + class_, bases, boost::noncopyable >("_DeviceActuator", "docstring", no_init); + class_, bases, boost::noncopyable >("WiimoteActuator", "docstring", no_init) + .def("reset", &av::daemon::WiimoteActuator::reset) + ; + class_, bases, boost::noncopyable >("DeviceService", "docstring") + .def("set_led", &av::daemon::DeviceService::setLED) + ; + + register_field("SFDeviceService"); + register_multifield("MFDeviceService"); + + // base classes (this classes cannot be instanciated from Python) + class_, bases, boost::noncopyable >("_Device", + "Avango Daemon base class for devices", no_init) + .def("add_station", &::addStation) + ; + class_, bases, boost::noncopyable >("_DeviceStation", + "An Avango Daemon station", no_init); + + // Avango NG device: HIDInput + class_, bases, boost::noncopyable >("_HIDHelper", + "A helper class that provides some basic properties as well as some functions to configure a HIDInput device.") + .add_property("device", &::getTTYFeature, &::setTTYFeature) + .add_property("norm_abs", &::getNormAbsFeature, &::setNormAbsFeature) + .add_property("accum_rel_events", &::getAccumRelFeature, &::setAccumRelFeature) + .add_property("reset_rel_values_cycle", &::getResetRelCycleFeature, &::setResetRelCycleFeature) + .add_property("timeout", &::getTimeoutFeature, &::setTimeoutFeature) + .def("map_to_station_button", &::mapToStationButton) + .def("map_to_station_value", &::mapToStationValue) + .def("map_to_station_led", &::mapToStationLED) + .def("set_led", &::setLED) + .def("set_leds", &::setAllLEDs) + ; + + // Avango NG device: WacomTablet (derived from HIDInput) + class_, bases, boost::noncopyable >("_WacomTabletHelper", + "A helper class that provides some basic properties and functions inherited from HIDInput.") + .add_property("toggle_reset", &::getToggleResetFeature, &::setToggleResetFeature) + ; + + // Avango NG device: Wiimote (derived from HIDInput) + class_, bases, boost::noncopyable >("_WiimoteHelper", + "A helper class that provides some basic properties and functions inherited from HIDInput.") + ; + + // Avango NG device: DTrack + class_, bases, boost::noncopyable >("_DTrackHelper", + "A helper class that provides some basic properties and function inherited from DTrack," + "used to construct a concrete Python device representation.") + .add_property("port", &::getPortFeature, &::setPortFeature) + ; + +#ifdef VRPN_SUPPORT + // Avango NG device: VRPNClient + class_, bases, boost::noncopyable >("_VRPNClientHelper", + "A helper class used to construct a concrete Python VRPN client device representation.") + .add_property("server", &::getServerFeature, &::setServerFeature) + ; +#endif + + // wrap helper function + def("does_type_exist", &::doesTypeExist); + + // start the daemon + def("run", &::run); +} diff --git a/avango-daemon/src/avango/daemon/DTrack.cpp b/avango-daemon/src/avango/daemon/DTrack.cpp new file mode 100644 index 00000000..8ec2f126 --- /dev/null +++ b/avango-daemon/src/avango/daemon/DTrack.cpp @@ -0,0 +1,286 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include "dtrack/dtrack.h" +#include +#include +#include +#include +#include +#include +#include + + + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::DTrack")); + + const size_t default_udp_bufsize = 10000; + const size_t default_udp_timeout = 1000000; // 1 sec +} + +AV_BASE_DEFINE(av::daemon::DTrack); + +av::daemon::DTrack::DTrack() : + mDTrack(new ::DTrack) +{ + mRequiredFeatures.push_back("port"); + mRequiredFeatures.push_back("timeout"); +} + +av::daemon::DTrack::~DTrack() +{} + +void +av::daemon::DTrack::initClass() +{ + if (!isTypeInitialized()) + { + av::daemon::Device::initClass(); + AV_BASE_INIT(av::daemon::Device, av::daemon::DTrack, true); + } +} + +/* virtual */ void +av::daemon::DTrack::startDevice() +{ + if (!parseFeatures()) + return; + + logger.info() << "startDevice: device configured successfully"; + + // initialize + dtrack_init_type ini; + + ini.udpport = mPort; + ini.udpbufsize = default_udp_bufsize; + ini.udptimeout_us = mTimeout; + + std::strcpy(ini.remote_ip, ""); + ini.remote_port = 0; + + if (int err = mDTrack->init(&ini)) + { + logger.error() << "startDevice: dtrack init error: %d", err; + stopDevice(); + return; + } + else + { + logger.info() << "startDevice: enabling cameras and calculation"; + mDTrack->send_udp_command(DTRACK_CMD_CAMERAS_AND_CALC_ON, 1); + } + + logger.info() << "startDevice: device initialized successfully"; +} + +/* virtual */ void +av::daemon::DTrack::readLoop() +{ + unsigned long framenr; + double timestamp; + int nbodycal; + int nbody; + dtrack_body_type* body = 0; + unsigned int max_bodies = 0; + int dummy; + unsigned int max_station_id = 1; + + while (mKeepRunning) + { + typedef NumStationMap::const_iterator station_map_it; + + for (station_map_it current = mStations.begin(); current != mStations.end(); ++current) + { + if (static_cast ((*current).first) > max_station_id) + max_station_id = (*current).first; + } + + if (max_bodies < max_station_id) + { + if (body) + ::free(body); + + max_bodies = max_station_id; + body = (dtrack_body_type*) ::malloc(sizeof(dtrack_body_type) * max_bodies); + } + + const int err = mDTrack->receive_udp_ascii(&framenr, ×tamp, &nbodycal, + &nbody, body, max_bodies, + &dummy, 0, 0, + &dummy, 0, 0, + &dummy, 0, 0); + if (DTRACK_ERR_NONE != err) + { + std::string msg; + + switch (err) + { + case DTRACK_ERR_UDP: msg = "error handling the udp socket"; break; + case DTRACK_ERR_MEM: msg = "error handling the udp buffer"; break; + case DTRACK_ERR_TIMEOUT: msg = "timeout while receiving data"; break; + case DTRACK_ERR_CMD: msg = "error while sending remote command"; break; + case DTRACK_ERR_PCK: msg = "error in udp packet"; break; + } + + logger.error() << "readLoop: dtrack: '%s'", msg.c_str(); + continue; + } + else + { + const unsigned int body_limit = std::min(static_cast (nbody), max_bodies); + + for (unsigned int i = 0; i < body_limit; ++i) + { + logger.trace() << "readLoop: detected body with ID = %s", body[i].id; + const int body_idx = body[i].id; + NumStationMap::iterator it = mStations.find(body_idx + 1); + + if (it != mStations.end()) + { + ::osg::Matrixf xform; + + xform.set(body[i].rot[0], body[i].rot[1], body[i].rot[2], 0.0f, + body[i].rot[3], body[i].rot[4], body[i].rot[5], 0.0f, + body[i].rot[6], body[i].rot[7], body[i].rot[8], 0.0f, + body[i].loc[0] * 0.001f, body[i].loc[1] * 0.001f, body[i].loc[2] * 0.001f, 1.0f); + + (*it).second->setMatrix(xform); + logger.trace() << "readLoop: set matrix of station number '%s'", body_idx + 1; + } + else logger.debug() << "readLoop: can't find station for body #%d (station not configured?)", body_idx; + } + } + } +} + +/* virtual */ void +av::daemon::DTrack::stopDevice() +{ + mDTrack->exit(); + logger.info() << "stopDevice: done."; +} + +unsigned long int +av::daemon::DTrack::convert_charpointer_to_ulong(const char* arg) const +{ + unsigned long int result = 0; + errno = 0; + + if (arg) + { + // man strtoul: + // ... + // The string must begin with an arbitrary amount of white space (as determined by isspace(3)) + // followed by a single optional '+' or '-' sign. If base is zero or 16, the string may then + // include a '0x' prefix, and the number will be read in base 16; otherwise, a zero base is + // taken as 10 (decimal) unless the next character is '0', in which case it is taken as 8 + // (octal). + static int base_magic(0); + + result = ::strtoul(arg, 0, base_magic); + + if (errno) + { + logger.warn() << "convert_charpointer_to_ulong: unable to convert arg '%s' to int; errno: '%s' ", + arg, std::strerror(errno); + result = 0; + } + else + LOG_TRACE(logger) << "convert_charpointer_to_ulong: converted arg '%s' to %ld", arg, result; + + } + else + logger.warn() << "convert_charpointer_to_ulong: got null pointer for arg conversion"; + + return result; +} + +const std::vector& +av::daemon::DTrack::queryFeatures() +{ + return mRequiredFeatures; +} + +bool +av::daemon::DTrack::parseFeatures() +{ + std::string port(queryFeature("port")); + if (port == "") + { + logger.warn() << "parseFeatures: feature 'port' not specified"; + return false; + } + else + { + logger.info() << "parseFeatures: configured feature 'port' = %s", port; + mPort = convert_charpointer_to_ulong(port.c_str()); + } + + std::string timeout(queryFeature("timeout")); + if (timeout == "") + { + logger.info() << "parseFeatures: feature 'timeout' not specified; using %d usec.",default_udp_timeout; + mTimeout = default_udp_timeout; + } + else mTimeout = convert_charpointer_to_ulong(timeout.c_str()); + + return true; +} + +// from readLoop +#if 0 +{ + logger.debug() << "readLoop: frame: %lu, stamp: %.3f, bodycal: %d, bodies: %d, sticks: %d, tools: %d, marker: %d", + framenr, timestamp, nbodycal, nbody, nflystick, nmeatool, nmarker; + + for (int i=0; i. * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::Device")); +} + +AV_BASE_DEFINE_ABSTRACT(av::daemon::Device); + +av::daemon::Device::Device() : + mKeepRunning(false), + mEmptyFeature(std::string("")), + mRunning(false) +{} + +av::daemon::Device::~Device() +{} + +void +av::daemon::Device::initClass() +{ + if (!isTypeInitialized()) + { + av::Typed::initClass(); + AV_BASE_INIT_ABSTRACT(av::Typed, av::daemon::Device, true); + } +} + +void +av::daemon::Device::addStation(int station_number, Station* station) +{ + mStations.insert(NumStationMap::value_type(station_number, station)); +} + +bool +av::daemon::Device::startUp() +{ + if(mRunning) return false; + + if(mStations.empty()) throw std::runtime_error("No station attached to this device."); + + startDevice(); + mKeepRunning = true; + mThread.reset(new Thread(boost::bind(&av::daemon::Device::threadFunction, this))); + mRunning = true; + return true; +} + +bool +av::daemon::Device::shutDown() +{ + if (!mRunning) return false; + + mKeepRunning = false; + stopDevice(); + + return true; +} + +bool +av::daemon::Device::isDeviceRunning() +{ + return mRunning; +} + +void +av::daemon::Device::threadFunction(Device* device) +{ + device->readLoop(); + device->mRunning = false; +} + +/* virtual */ std::string +av::daemon::Device::getStationName(int id) +{ + NumStationMap::iterator found = mStations.find(id); + if (found != mStations.end()) + return found->second->getName(); + else + return ""; +} + +/* virtual */ void +av::daemon::Device::configureFeature(const std::string& feature, const std::string& value) +{ + mFeatures[feature] = value; +} + +/* virtual */ void +av::daemon::Device::unconfigureFeature(const std::string& feature) +{ + mFeatures.erase(feature); +} + +/* virtual */ std::string +av::daemon::Device::queryFeature(const std::string& feature) +{ + StringStringMap::iterator i = mFeatures.find(feature); + return (i != mFeatures.end()) ? (*i).second : mEmptyFeature; +} diff --git a/avango-daemon/src/avango/daemon/DeviceActuator.cpp b/avango-daemon/src/avango/daemon/DeviceActuator.cpp new file mode 100644 index 00000000..4963dd6d --- /dev/null +++ b/avango-daemon/src/avango/daemon/DeviceActuator.cpp @@ -0,0 +1,65 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include + + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::DeviceActuator")); +} + +AV_FC_DEFINE(av::daemon::DeviceActuator); + +av::daemon::DeviceActuator::DeviceActuator() +{ + AV_FC_ADD_FIELD(DeviceService, 0); + AV_FC_ADD_FIELD(Station, ::std::string()); +} + +av::daemon::DeviceActuator::~DeviceActuator() +{} + +void +av::daemon::DeviceActuator::initClass() +{ + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, av::daemon::DeviceActuator, true); + } +} + +/* virtual */ void +av::daemon::DeviceActuator::fieldHasChanged(const av::Field& field) +{ + if (&field == &DeviceService) + mService = DeviceService.getValue(); + else if (&field == &Station) + mStation = Station.getValue(); +} diff --git a/avango-daemon/src/avango/daemon/DeviceDaemon.cpp b/avango-daemon/src/avango/daemon/DeviceDaemon.cpp new file mode 100644 index 00000000..b66eb789 --- /dev/null +++ b/avango-daemon/src/avango/daemon/DeviceDaemon.cpp @@ -0,0 +1,105 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace av::logging; + +namespace po = boost::program_options; + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::DeviceDaemon")); + + void + printVersion() + { + std::cout << "AvangoDaemon Version " + << AVANGO_DAEMON_VERSION_MAJOR + << "." << AVANGO_DAEMON_VERSION_MINOR + << "." << AVANGO_DAEMON_VERSION_MAINT + << std::endl; + } +} + + +AV_BASE_DEFINE(av::daemon::DeviceDaemon); + +av::daemon::DeviceDaemon::DeviceDaemon() +{} + +av::daemon::DeviceDaemon::~DeviceDaemon() +{} + +void +av::daemon::DeviceDaemon::initClass() +{ + if (!isTypeInitialized()) + { + av::Base::initClass(); + AV_BASE_INIT(av::Base, av::daemon::DeviceDaemon, true); + } +} + +void +av::daemon::DeviceDaemon::appendDevice(Device* device) +{ + mDevices.push_back(Link(device)); +} + +void +av::daemon::DeviceDaemon::run() +{ + // print info string + printVersion(); + std::cout << "Press 'q' to stop daemon." << std::endl; + + // start all devices + for (std::vector >::iterator iter = mDevices.begin(); iter != mDevices.end(); ++iter) + (*iter)->startUp(); + + // wait for 'exit' command + char key = 0; + while (key != 'q') + { + std::cin >> key; + } + + // shutdown all devices + for (std::vector >::iterator iter = mDevices.begin(); iter != mDevices.end(); ++iter) + (*iter)->shutDown(); +} diff --git a/avango-daemon/src/avango/daemon/DeviceSensor.cpp b/avango-daemon/src/avango/daemon/DeviceSensor.cpp new file mode 100644 index 00000000..d264c017 --- /dev/null +++ b/avango-daemon/src/avango/daemon/DeviceSensor.cpp @@ -0,0 +1,257 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include + + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::DeviceSensor")); +} + +AV_FC_DEFINE(av::daemon::DeviceSensor); + +av::daemon::DeviceSensor::DeviceSensor() +{ + AV_FC_ADD_FIELD(DeviceService, 0); + AV_FC_ADD_FIELD(Station, ::std::string()); + AV_FC_ADD_FIELD(ResetValuesOnRead, false); + AV_FC_ADD_FIELD(Matrix, ::osg::Matrix()); + AV_FC_ADD_FIELD(Button0, false); + AV_FC_ADD_FIELD(Button1, false); + AV_FC_ADD_FIELD(Button2, false); + AV_FC_ADD_FIELD(Button3, false); + AV_FC_ADD_FIELD(Button4, false); + AV_FC_ADD_FIELD(Button5, false); + AV_FC_ADD_FIELD(Button6, false); + AV_FC_ADD_FIELD(Button7, false); + AV_FC_ADD_FIELD(Button8, false); + AV_FC_ADD_FIELD(Button9, false); + AV_FC_ADD_FIELD(Button10, false); + AV_FC_ADD_FIELD(Button11, false); + AV_FC_ADD_FIELD(Button12, false); + AV_FC_ADD_FIELD(Button13, false); + AV_FC_ADD_FIELD(Button14, false); + AV_FC_ADD_FIELD(Button15, false); + AV_FC_ADD_FIELD(Button16, false); + AV_FC_ADD_FIELD(Button17, false); + AV_FC_ADD_FIELD(Button18, false); + AV_FC_ADD_FIELD(Button19, false); + AV_FC_ADD_FIELD(Button20, false); + AV_FC_ADD_FIELD(Button21, false); + AV_FC_ADD_FIELD(Button22, false); + AV_FC_ADD_FIELD(Button23, false); + AV_FC_ADD_FIELD(Button24, false); + AV_FC_ADD_FIELD(Button25, false); + AV_FC_ADD_FIELD(Button26, false); + AV_FC_ADD_FIELD(Button27, false); + AV_FC_ADD_FIELD(Button28, false); + AV_FC_ADD_FIELD(Button29, false); + AV_FC_ADD_FIELD(Button30, false); + AV_FC_ADD_FIELD(Button31, false); + AV_FC_ADD_FIELD(Value0, 0.0f); + AV_FC_ADD_FIELD(Value1, 0.0f); + AV_FC_ADD_FIELD(Value2, 0.0f); + AV_FC_ADD_FIELD(Value3, 0.0f); + AV_FC_ADD_FIELD(Value4, 0.0f); + AV_FC_ADD_FIELD(Value5, 0.0f); + AV_FC_ADD_FIELD(Value6, 0.0f); + AV_FC_ADD_FIELD(Value7, 0.0f); + AV_FC_ADD_FIELD(Value8, 0.0f); + AV_FC_ADD_FIELD(Value9, 0.0f); + AV_FC_ADD_FIELD(Value10, 0.0f); + AV_FC_ADD_FIELD(Value11, 0.0f); + AV_FC_ADD_FIELD(Value12, 0.0f); + AV_FC_ADD_FIELD(Value13, 0.0f); + AV_FC_ADD_FIELD(Value14, 0.0f); + AV_FC_ADD_FIELD(Value15, 0.0f); + AV_FC_ADD_FIELD(LED0, false); + AV_FC_ADD_FIELD(LED1, false); + AV_FC_ADD_FIELD(LED2, false); + AV_FC_ADD_FIELD(LED3, false); + AV_FC_ADD_FIELD(LED4, false); + AV_FC_ADD_FIELD(LED5, false); + AV_FC_ADD_FIELD(LED6, false); + AV_FC_ADD_FIELD(LED7, false); + AV_FC_ADD_FIELD(LED8, false); + AV_FC_ADD_FIELD(LED9, false); + AV_FC_ADD_FIELD(LED10, false); + AV_FC_ADD_FIELD(LED11, false); + AV_FC_ADD_FIELD(LED12, false); + AV_FC_ADD_FIELD(LED13, false); + AV_FC_ADD_FIELD(LED14, false); + AV_FC_ADD_FIELD(LED15, false); + AV_FC_ADD_FIELD(TransmitterOffset, ::osg::Matrix()); + AV_FC_ADD_FIELD(ReceiverOffset, ::osg::Matrix()); + AV_FC_ADD_FIELD(Rotation, ::osg::Quat()); + AV_FC_ADD_FIELD(Translation, ::osg::Vec3()); + + alwaysEvaluate(true); +} + +av::daemon::DeviceSensor::~DeviceSensor() +{} + +void +av::daemon::DeviceSensor::initClass() +{ + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, av::daemon::DeviceSensor, true); + } +} + +/* virtual */ void +av::daemon::DeviceSensor::evaluate() +{ + if (DeviceService.getValue().isValid() && !(Station.getValue().empty()) ) + { + updateMatrix(); + updateButtons(); + updateValues(); + updateLEDs(); + } +} + +void +av::daemon::DeviceSensor::updateMatrix() +{ + ::osg::Matrixf mat; + getMatrix(mat); + + if (Matrix.getValue() != mat) + { + ::osg::Quat rot = mat.getRotate(); + ::osg::Vec3 pos = mat.getTrans(); + + Rotation.setValue(rot); + Translation.setValue(pos); + Matrix.setValue(mat); + } +} + +void +av::daemon::DeviceSensor::updateButtons() +{ + for (int i=0; i* sf = dynamic_cast*>(getField(fieldname.str())); + + if ( (sf != 0) && (getButton(i) != sf->getValue()) ) + sf->setValue(getButton(i)); + } +} + +void +av::daemon::DeviceSensor::updateValues() +{ + for (int i=0; i* sf = dynamic_cast*>(getField(fieldname.str())); + + if ( (sf != 0) && (getValue(i) != sf->getValue()) ) + sf->setValue(getValue(i)); + } +} + +void +av::daemon::DeviceSensor::updateLEDs() +{ + for (int i=0; i* sf = dynamic_cast*>(getField(fieldname.str())); + + if ( (sf != 0) && (getLED(i) != sf->getValue()) ) + sf->setValue(getLED(i)); + } +} + +void +av::daemon::DeviceSensor::getMatrix(::osg::Matrixf& mat) +{ + const char* stationstr = Station.getValue().c_str(); + mat = DeviceService.getValue()->getMatrix(stationstr); + + mat.preMult(ReceiverOffset.getValue()); + mat.postMult(TransmitterOffset.getValue()); +} + +float +av::daemon::DeviceSensor::getValue(int v) +{ + if((v >= 0) && (v < sMaxValues)) + { + const char* stationstr = Station.getValue().c_str(); + float value = DeviceService.getValue()->getValue(stationstr, v); + if (ResetValuesOnRead.getValue()) DeviceService.getValue()->setValue(stationstr, v, 0.0f); + return value; + } + + return 0.0f; +} + +bool +av::daemon::DeviceSensor::getButton(int b) +{ + if ((b >= 0) && (b < sMaxButtons)) + { + const char* stationstr = Station.getValue().c_str(); + return DeviceService.getValue()->getButton(stationstr, b); + } + + return false; +} + +bool +av::daemon::DeviceSensor::getLED(int l) +{ + if ((l >= 0) && (l < sMaxLEDs)) + { + const char* stationstr = Station.getValue().c_str(); + return DeviceService.getValue()->getLED(stationstr, l); + } + + return false; +} + +void +av::daemon::DeviceSensor::setLED(int l, bool val) +{ + if ((l >= 0) && (l < sMaxLEDs)) + { + const char* stationstr = Station.getValue().c_str(); + DeviceService.getValue()->setLED(stationstr, l, val); + } +} diff --git a/avango-daemon/src/avango/daemon/DeviceService.cpp b/avango-daemon/src/avango/daemon/DeviceService.cpp new file mode 100644 index 00000000..afaedd0a --- /dev/null +++ b/avango-daemon/src/avango/daemon/DeviceService.cpp @@ -0,0 +1,303 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +// includes, system +#include +#include +#include + +// includes, project +#include +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::DeviceService")); + + typedef std::list station_segment_list_type; + station_segment_list_type station_segment_list; + + extern "C" void remove_remaining_station_segments() + { + while (!station_segment_list.empty()) + { + logger.debug() << "remove_remaining_station_segments: destructing 'fpStationSegment' @" + << static_cast (*(station_segment_list.begin())); + + delete *(station_segment_list.begin()); + station_segment_list.pop_front(); + } + } +} + +AV_BASE_DEFINE(av::daemon::DeviceService); + +AV_FIELD_DEFINE(av::daemon::SFDeviceService); +AV_FIELD_DEFINE(av::daemon::MFDeviceService); + +av::daemon::DeviceService::DeviceService() + : mIdentityMatrix(new ::osg::Matrixf()), + mCachedStationName(0), + mCachedStation(0), + mStationSegment(0) +{ + connectDaemon(); +} + +/* virtual */ +av::daemon::DeviceService::~DeviceService() +{ + disconnectDaemon(); +} + +/* static */ void +av::daemon::DeviceService::initClass() +{ + if (!isTypeInitialized()) + { + Base::initClass(); + AV_BASE_INIT(av::Base, av::daemon::DeviceService, true); + } +} + +void +av::daemon::DeviceService::connectDaemon() +{ + disconnectDaemon(); + mStationSegment = new StationSegment; + station_segment_list.push_back(mStationSegment); +} + +void +av::daemon::DeviceService::disconnectDaemon() +{ + station_segment_list.remove(mStationSegment); + delete mStationSegment; + mStationSegment = 0; + clearStationCache(); +} + +void +av::daemon::DeviceService::clearStationCache() +{ + mCachedStationName = 0; + mCachedStation = 0; +} + +av::daemon::Station* +av::daemon::DeviceService::lookupCachedStation(const char* station_name) +{ + if (station_name == mCachedStationName) + { + logger.trace() << "lookupCachedStation(): " << this << " cache hit for station " << station_name; + return mCachedStation; + + } + else if (mStationSegment) + { + logger.trace() << "lookupCachedStation(): " << this << " cache miss for station " << station_name; + Station* station = mStationSegment->getStation(station_name); + + if (station) + { + mCachedStationName = station_name; + mCachedStation = station; + return station; + } + else + { + clearStationCache(); + logger.warn() << "lookupCachedStation(): station " << station_name << " not found; cache cleared."; + return 0; + } + } + else + { + logger.warn() << "lookupCachedStation(): no station segment initialized."; + } + + return 0; +} + +const osg::Matrixf& +av::daemon::DeviceService::getMatrix(const char* station_name) +{ + if (mStationSegment) + { + const Station* station = lookupCachedStation (station_name); + + if (station) + { + logger.trace() << "getMatrix(): " << this << " succeeded for station " << station_name; + return station->getMatrix(); + } + else logger.warn() << "getMatrix(): " << this << " failed for station " << station_name << " (no station)"; + } + else logger.warn() << "getMatrix(): " << this << " failed for station " << station_name << " (no segment)"; + + return *mIdentityMatrix; +} + +int +av::daemon::DeviceService::getButton(const char* station_name, int which) +{ + if (mStationSegment) + { + const Station* station = lookupCachedStation(station_name); + + if (station) return station->getButton(which); + } else logger.warn() << "getButton(): no station segment initialized."; + + return 0; +} + +float +av::daemon::DeviceService::getValue(const char* station_name, int which) +{ + if (mStationSegment) + { + const Station* station = lookupCachedStation(station_name); + + if (station) return station->getValue(which); + } else logger.warn() << "getValue(): no station segment initialized."; + + return 0.0f; +} + +bool +av::daemon::DeviceService::getLED(const char* station_name, int which) +{ + if (mStationSegment) + { + const Station* station = lookupCachedStation(station_name); + + if (station) return station->getLED(which); + } else logger.warn() << "getLED(): no station segment initialized."; + + return false; +} + +void +av::daemon::DeviceService::setMatrix(const char* station_name, const ::osg::Matrixf& value) +{ + if (mStationSegment) + { + Station* station = lookupCachedStation (station_name); + + if (station) + { + station->setMatrix(value); + logger.info() << "setMatrix(): " << this << " succeeded for station " << station_name; + } + else logger.warn() << "setMatrix(): " << this << " failed for station " << station_name << " (no station)"; + } + else logger.warn() << "setMatrix(): " << this << " failed for station " << station_name << " (no segment)"; +} + +void +av::daemon::DeviceService::setButton(const char* station_name, int which, bool value) +{ + if (mStationSegment) + { + Station* station = lookupCachedStation(station_name); + + if (station) station->setButton(which, value); + } else logger.warn() << "setButton(): no station segment initialized."; +} + +void +av::daemon::DeviceService::setValue(const char* station_name, int which, float value) +{ + if (mStationSegment) + { + Station* station = lookupCachedStation(station_name); + + if (station) station->setValue(which, value); + } else logger.warn() << "setValue(): no station segment initialized."; +} + +void +av::daemon::DeviceService::setLED(const char* station_name, int which, bool value) +{ + if (mStationSegment) + { + Station* station = lookupCachedStation(station_name); + + if (station) station->setLED(which, value); + } else logger.warn() << "setLED(): no station segment initialized."; +} + +bool +av::daemon::DeviceService::getMatrixUsed(const char* station_name) +{ + if (mStationSegment) + { + const Station* station = lookupCachedStation(station_name); + + if (station) return station->getMatrixUsed(); + } else logger.warn() << "getMatrixUsed(): no station segment initialized."; + + return false; +} + +int +av::daemon::DeviceService::getButtonsUsed(const char* station_name) +{ + if (mStationSegment) + { + const Station* station = lookupCachedStation(station_name); + + if (station) return station->getButtonsUsed(); + } else logger.warn() << "getButtonsUsed(): no station segment initialized."; + + return 0; +} + +int +av::daemon::DeviceService::getValuesUsed(const char* station_name) +{ + if (mStationSegment) + { + const Station* station = lookupCachedStation(station_name); + + if (station) return station->getValuesUsed(); + } else logger.warn() << "getValuesUsed(): no station segment initialized."; + + return 0; +} + +int +av::daemon::DeviceService::getLEDsUsed(const char* station_name) +{ + if (mStationSegment) { + const Station* station = lookupCachedStation(station_name); + + if (station) return station->getLEDsUsed(); + } else logger.warn() << "getLEDsUsed(): no station segment initialized."; + + return 0; +} diff --git a/avango-daemon/src/avango/daemon/HIDInput.cpp b/avango-daemon/src/avango/daemon/HIDInput.cpp new file mode 100644 index 00000000..946dbac2 --- /dev/null +++ b/avango-daemon/src/avango/daemon/HIDInput.cpp @@ -0,0 +1,1449 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TEST_BIT(bit, array) (array[bit/8] & (1 << (bit % 8))) + +namespace { + + av::Logger& logger(av::getLogger("av::daemon::HIDInput")); + + const int KIND_BUTTON = 0; + const int KIND_VALUE = 1; + const int KIND_LED = 2; + + // these two defines are used for packing two unsigned shorts into one unsigned int + + // bits to left-shift hi short (16) + const unsigned int HIDINPUT_HI_SHIFT = sizeof (unsigned short)*8; + // mask to filter lo unsigned short (0xFFFF) + const unsigned int HIDINPUT_LO_MASK = USHRT_MAX; + +} + +AV_BASE_DEFINE(av::daemon::HIDInput); + +av::daemon::HIDInput::HIDInput() : + mFd(-1) +{} + +av::daemon::HIDInput::~HIDInput() +{ + stopDevice(); +} + +void +av::daemon::HIDInput::initClass() +{ + if (!isTypeInitialized()) + { + av::daemon::Device::initClass(); + AV_BASE_INIT(av::daemon::Device, av::daemon::HIDInput, true); + } +} + +bool +av::daemon::HIDInput::open() +{ + close(); + + if (-1 == (mFd = ::open(mTty.c_str(), O_RDWR|O_NONBLOCK))) { + logger.error() << "open: failed for " << mTty.c_str() << " with reason: " << ::strerror(errno); + return false; + } + logger.info() << "open: opened " << mTty.c_str() << " (fd: " << mFd << ")"; + + struct input_id device_info; + + if (-1 == ioctl(mFd, EVIOCGID, &device_info)) { + logger.error() << "open: ioctl(EVIOCGID) failed with reason: " << ::strerror(errno); + close(); + return false; + } + logger.info() << "open: found device " + << std::hex << device_info.vendor << ":" + << std::hex << device_info.product + << " on " << mTty.c_str() + << " (fd: " << mFd << ")"; + return true; +} + +bool +av::daemon::HIDInput::isOpen() const +{ + return (-1 != mFd); +} + +bool +av::daemon::HIDInput::close() +{ + if (isOpen()) + { + (void) ::close(mFd); + logger.info() << "close: closed " << mTty.c_str() << " (fd: " << mFd << ")"; + mFd = -1; + } + + return (-1 == mFd) ? true : false; +} + +bool +av::daemon::HIDInput::readEvent(struct input_event* event) +{ + if (isOpen() && event) + { + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(mFd, &rfds); + + struct timeval timeout = { 0, mTimeout*1000 }; + + switch (::select(mFd + 1, &rfds, 0, 0, &timeout)) + { + case 0: + logger.trace() << "read: select(2) timed out after " << timeout.tv_sec + << " sec for " << mTty.c_str(); + break; + + case -1: + logger.warn() << "read: select(2) failed for " << mTty.c_str() + << " with reason: " << ::strerror(errno) << " (" << errno << ")"; + close(); + break; + + default: + if (sizeof(input_event) != ::read(mFd, event, sizeof(input_event))) + { + logger.warn() << "read: select(2) failed for " << mTty.c_str() + << " with reason: " << ::strerror(errno) << " (" << errno << ")"; + close(); + } + else + { + return true; + } + break; + } + } + return false; +} + +bool +av::daemon::HIDInput::writeEvent(const struct input_event& event) +{ + if (isOpen()) + { + ssize_t retval = ::write(mFd, &event, sizeof(input_event)); + + switch (retval) + { + case sizeof(input_event): + logger.trace() << "writeEvent: success for " << mTty.c_str(); + return true; + break; + default: + logger.warn() << "writeEvent: write(2) failed for " << mTty.c_str() + << " with reason: " << ::strerror(errno) << " (" << errno << ")"; + close(); + break; + } + } + return false; +} + +namespace av +{ + namespace daemon + { + template <> + unsigned int + HIDInput::scanForOptionalFeature(const std::string& feature, unsigned int default_value) + { + std::string feature_value = queryFeature(feature); + unsigned int return_value = default_value; + + if (!scanUnsignedInteger(feature_value, return_value)) + { + logger.info() << "scanForOptionalFeature: feature " << feature.c_str() + << " not specified, using default of " << default_value; + return default_value; + } + return return_value; + } + + template <> + int + HIDInput::scanForOptionalFeature(const std::string& feature, int default_value) + { + std::string feature_value = queryFeature(feature); + int return_value = default_value; + + if (!scanInteger(feature_value, return_value)) + { + logger.info() << "scanForOptionalFeature: feature " << feature.c_str() + << " not specified, using default of " << default_value; + return default_value; + } + return return_value; + } + + template <> + bool + HIDInput::scanForOptionalFeature(const std::string& feature, bool default_value) + { + std::string feature_value = queryFeature(feature); + unsigned int scanned_value = default_value; + + if (!scanUnsignedInteger(feature_value, scanned_value)) + { + logger.info() << "scanForOptionalFeature: feature " << feature.c_str() + << " not specified, using default of " << (default_value ? 1 : 0); + return default_value; + } + return scanned_value == 0 ? false : true; + } + + template <> + std::string + HIDInput::scanForRequiredFeature(const std::string& feature) + { + std::string feature_value = queryFeature(feature); + + if (feature_value.empty()) + { + logger.info() << "scanForRequiredFeature: feature " << feature.c_str() << " not specified."; + throw 1; + } + return feature_value; + } + + template <> + unsigned int + HIDInput::scanForRequiredFeature(const std::string& feature) + { + std::string feature_value = queryFeature(feature); + unsigned int return_value = 0; + + if (!scanUnsignedInteger(feature_value, return_value)) + { + logger.info() << "scanForRequiredFeature: feature " << feature.c_str() << " not specified."; + throw 1; + } + return return_value; + } + } +} + +/*virtual*/ int +av::daemon::HIDInput::parse_features() +{ + try + { + mTty = scanForRequiredFeature("tty"); + } + catch (int err) + { + return 0; + } + + mNormAbs = scanForOptionalFeature("norm-abs", true); + mAccumRel = scanForOptionalFeature("accum-rel-events", false); + mResetRelCycle = scanForOptionalFeature("reset-rel-values-cycle", 0); + mTimeout = scanForOptionalFeature("timeout", 200); + + return 1; +} + +/* virtual */ void +av::daemon::HIDInput::retrieve_abs_info() +{ + uint8_t bitmask[ABS_MAX/CHAR_BIT + 1] = { 0 }; + input_absinfo abs_info; + + if (-1 == ioctl(mFd, EVIOCGBIT(EV_ABS, sizeof(bitmask)), bitmask)) + { + logger.warn() << "retrieve_abs_info: ioctl(EVIOCGBIT(EV_ABS)) failed with reason: " + << ::strerror(errno); + return; + } + + for (int loop = 0; loop < ABS_MAX; loop++) { + if (TEST_BIT(loop, bitmask)) { + // test is o.k. -> feature available + // retrieve information + if (-1 == ioctl(mFd, EVIOCGABS(loop), &abs_info)) + { + logger.warn() << "retrieve_abs_info: ioctl(EVIOCGABS) failed with reason: " + << ::strerror(errno); + } + else + { + // store information in map + mAbsInfoMap[loop] = abs_info; + } + } + } +} + +/* virtual */ void +av::daemon::HIDInput::startDevice() +{} + +/* virtual */ void +av::daemon::HIDInput::readLoop() +{ + if (!parse_features()) + { + logger.warn() << "startDevice: required features missing, not started."; + return; + } + + NumStationMap::iterator ns; + struct input_event event; + int reset_wait_counter(0); + + for (;;) + { + while (!isOpen()) + { + if (open()) + { + retrieve_abs_info(); + stopLEDs(); + startLEDs(); + } + else + { + logger.warn() << "readLoop: HID device is not open."; + // sleep 5 seconds + struct timeval timeout = { 5, 0 }; + while (0 != ::select(0, 0, 0, 0, &timeout)) {} + } + } + + updateLEDs(); + if (readEvent(&event)) { + reset_wait_counter = 0; + logger.trace() << "readLoop: time " << event.time.tv_sec << "." << event.time.tv_usec + << ", type " << event.type << ", code " << event.code << ", value " << event.value; + + for (ns = mStations.begin(); ns != mStations.end(); ++ns) + { + int station_index = ns->first; + if (!stationLooksForEvent(station_index, event)) { + continue; + } + applyEventToStation(station_index, event); + } + } + else + { // timeout + ++reset_wait_counter; + + // reset all EV_REL mappings to 0.0 if not accumulating relative values + if (!mAccumRel && (mResetRelCycle >= 0) && (reset_wait_counter >= mResetRelCycle)) + { + reset_wait_counter = 0; + clearRelativeStationValues(); + logger.trace() << "readLoop: resetting all EV_REL mappings."; + } + } + } +} + +void +av::daemon::HIDInput::stopDevice() +{ + if (isOpen()) + { + stopLEDs(); + close(); + logger.info() << "stopDevice: done."; + } +} + +/* virtual */ void +av::daemon::HIDInput::addStation(int station_number, Station* station) +{ + // add station normally + Device::addStation(station_number, station); + + // create mapping lookups for station + mStationHIDMappingLookup.insert(StationHIDMappingLookup::value_type(station_number, mDefaultHIDMapping)); + mStationHIDLEDMappingLookup.insert(StationHIDLEDMappingLookup::value_type(station_number, mDefaultHIDLEDMapping)); + + // create last led state lookup for station + mLastLEDStateLookup.insert(LastLEDStateLookup::value_type(station, station->getLEDs())); +} + +/* virtual */ +std::string +av::daemon::HIDInput::getFirstStation() +{ + if (mStations.size() > 0) + return mStations.begin()->second->getName(); + else + return ""; +} + +/* virtual */ void +av::daemon::HIDInput::configureFeature(const std::string& feature, const std::string& value) +{ + // we have to check if this is a mapping request + // feature must be "station::kind::index" and + // value must be "eventType::eventCode" + std::string::size_type pos1 = feature.find("::"); + std::string::size_type pos2 = feature.rfind("::"); + bool is_mapping_feature = + (pos1 != std::string::npos) && + (pos2 != std::string::npos) && + (pos2 >= pos1 + 2); + std::string::size_type pos3 = value.find("::"); + bool is_mapping_value = pos3 != std::string::npos; + + if (is_mapping_feature && is_mapping_value) + { + logger.debug() << "configureFeature: configuring feature " << feature.c_str() + << " = " << value.c_str(); + processMappingRequest(feature, value); + } + else if (feature=="call") + { + if (value=="print-maps") printMaps(); + else if (value=="print-abs") printAbsInfo(); + else logger.warn() << "configureFeature: unknown call " << value.c_str(); + } + else + { + Device::configureFeature(feature,value); + } +} + +/* virtual */ std::string +av::daemon::HIDInput::queryFeature(const std::string& feature) +{ + if (feature == "status") + { + static std::string status; + status = (isOpen() ? "RUNNING" : "NOT RUNNING"); + return status; + } + else + { + return Device::queryFeature(feature); + } +} + +const std::vector& +av::daemon::HIDInput::queryFeatures() +{ + return mFeatures; +} + +void +av::daemon::HIDInput::processMappingRequest(const std::string& feature, const std::string& value) +{ + std::string station; + std::string kind; + std::string index; + std::string type; + std::string code; + + bool valid = true; + + logger.debug() << "configureFeature: got feature " << feature.c_str() << " = " + << value.c_str() << " for processing."; + + try + { + // feature + std::string::size_type feature_lower = 0; + std::string::size_type feature_upper = feature.find("::"); + if (feature_upper == std::string::npos) + throw 1; + + station = feature.substr(feature_lower, feature_upper); + feature_lower = feature_upper + 2; + feature_upper = feature.find("::", feature_lower); + if (feature_upper == std::string::npos) + throw 1; + + kind = feature.substr(feature_lower, feature_upper - feature_lower); + feature_lower = feature_upper + 2; + index = feature.substr(feature_lower); + + // value + std::string::size_type value_lower = 0; + std::string::size_type value_upper = value.find("::"); + if (value_upper == std::string::npos) + throw 1; + + type = value.substr(value_lower, value_upper); + value_lower = value_upper + 2; + code = value.substr(value_lower); + } + catch (int err) + { + valid = false; + } + + valid = valid && !station.empty() && !kind.empty() && !index.empty() && !type.empty() && !code.empty(); + + if (!valid) logger.warn() << "processMappingRequest: " << feature.c_str() << " , " << value.c_str() << " invalid."; + else + { + LOG_TRACE(logger) << "processMappingRequest: before conv. t: " << type.c_str() + << ", c: " << code.c_str() << ", k: " << kind.c_str() + << ", i: " << index.c_str(); + + unsigned short eventType = LinuxEvent::getEventCode(type.c_str()); + unsigned short eventCode = LinuxEvent::getEventCode(code.c_str()); + unsigned short kind_value = LinuxEvent::getEventCode(kind.c_str()); + unsigned short index_value = convert_charpointer_to_ulong(index.c_str()); + unsigned int eventPair = pack_into_uint(eventType, eventCode); + unsigned int stationPair = pack_into_uint(kind_value, index_value); + + LOG_TRACE(logger) << "processMappingRequest: after conv. t: " << eventType + << ", c: " << eventCode << ", k: " << kind_value + << ", i: " << index_value; + + // sanity check + switch (kind_value) + { + case KIND_BUTTON: + if (index_value >= Station::sMaxButtons) + { + logger.warn() << "processMappingRequest: Button index must be in range [0," + << av::daemon::Station::sMaxButtons - 1 << "]!"; + return; + } + break; + case KIND_VALUE: + if (index_value >= Station::sMaxValues) + { + logger.warn() << "processMappingRequest: Value index must be in range [0," + << av::daemon::Station::sMaxValues - 1 << "]!"; + return; + } + break; + case KIND_LED: + if (index_value >= Station::sMaxLeds) + { + logger.warn() << "processMappingRequest: LED index must be in range [0," + << av::daemon::Station::sMaxLeds - 1 << "]!"; + return; + } + if (eventType != EV_LED) + { + logger.warn() << "processMappingRequest: event type for STATION_LED must be EV_LED"; + return; + } + break; + default: + { + logger.warn() << "processMappingRequest: Kind must be either Button (0) or Value (1) !"; + return; + } + } + + logger.debug() << "processMappingRequest: '" << station.c_str() << "::" << kind_value + << "::" << index_value << "' <- '" << eventType << "::" << eventCode << "'"; + + if (station == "default") + { + // insert mapping into default mapping table + if (kind_value == KIND_LED) + { + // doing reversed lookups for LEDs + if (mDefaultHIDLEDMapping.find(stationPair) != mDefaultHIDLEDMapping.end()) + mDefaultHIDLEDMapping.erase(stationPair); + mDefaultHIDLEDMapping.insert(HIDLEDMapping::value_type(stationPair,eventPair)); + } + else + { + if (mDefaultHIDMapping.find(eventPair) != mDefaultHIDMapping.end()) + mDefaultHIDMapping.erase(eventPair); + mDefaultHIDMapping.insert(HIDMapping::value_type(eventPair,stationPair)); + } + } else { + // insert mapping into station mapping table + // find mapping lookup for the station (by name) + NumStationMap::iterator ns; + int station_id = -1; + + for (ns = mStations.begin(); ns != mStations.end(); ++ns) { + if (0 == std::strcmp((*ns).second->getName(),station.c_str())) { + station_id = (*ns).first; + break; + } + } + + if (station_id>=0) { + if (kind_value == KIND_LED) { + // doing reversed lookups for LEDs + StationHIDLEDMappingLookup::iterator i = mStationHIDLEDMappingLookup.find(station_id); + if (i == mStationHIDLEDMappingLookup.end()) + logger.warn() << "processMappingRequest: can't get HIDLEDMappingLookup for station " + << station_id << " (" << station.c_str() << ")"; + else + { + // we found the mapping + HIDLEDMapping& hidmapping = (*i).second; + if (hidmapping.find(stationPair) != hidmapping.end()) + hidmapping.erase(stationPair); + hidmapping.insert(HIDLEDMapping::value_type(stationPair,eventPair)); + } + } + else + { + StationHIDMappingLookup::iterator i = mStationHIDMappingLookup.find(station_id); + if (i == mStationHIDMappingLookup.end()) + logger.warn() << "processMappingRequest: can't get HIDMappingLookup for station " + << station_id << " (" << station.c_str() << ")"; + else + { + // we found the mapping + HIDMapping& hidmapping = (*i).second; + if (hidmapping.find(eventPair) != hidmapping.end()) + hidmapping.erase(eventPair); + hidmapping.insert(HIDMapping::value_type(eventPair,stationPair)); + } + } + } + else + { + logger.warn() << "processMappingRequest: can't find station " << station.c_str(); + } + } + } +} + +void +av::daemon::HIDInput::printAbsInfo() const +{ + if (0 == mAbsInfoMap.size()) { + logger.warn() << "printAbsInfo: No Absolute Axes available."; + return; + } + + logger.info() << "printAbsInfo: Absolute Axes: "; + + AbsInfoMap::const_iterator current = mAbsInfoMap.begin(); + while (current != mAbsInfoMap.end()) + { + const input_absinfo& info = (*current).second; + logger.info() << eventPairToString(EV_ABS, (*current).first).c_str() << " : " + << info.value << " " << info.minimum << " " << info.maximum + << " " << info.fuzz << " " << info.flat; + ++current; + } +} + +void +av::daemon::HIDInput::printHIDMapping(const HIDMapping& hidmapping) const +{ + logger.info() << "printHIDMapping: HID->StationSegment map: "; + + HIDMapping::const_iterator current = hidmapping.begin(); + unsigned short evType; + unsigned short evCode; + unsigned short kind; + unsigned short index; + + while (current != hidmapping.end()) + { + unpack_from_uint((*current).first, evType, evCode); + unpack_from_uint((*current).second, kind, index); + logger.info() << eventPairToString(evType, evCode).c_str() << " -> " + << stationPairToString(kind, index).c_str() << " ('" + << evType << "::" << evCode << " -> " << kind << "::" << index << "')"; + ++current; + } +} + +void +av::daemon::HIDInput::printStatus() const +{ + logger.info() << "printStatus: " + << (isOpen() ? "OK" : "NOT RUNNING"); +} + +// packs two ushorts into one uint +unsigned int +av::daemon::HIDInput::pack_into_uint(unsigned short v1,unsigned short v2) const +{ + return ((v1 << HIDINPUT_HI_SHIFT) | v2); +} +// unpacks one uint into two ushorts +void +av::daemon::HIDInput::unpack_from_uint(unsigned int v,unsigned short& v1,unsigned short& v2) const +{ + v1 = v >> HIDINPUT_HI_SHIFT; + v2 = v & HIDINPUT_LO_MASK; +} + +unsigned long int +av::daemon::HIDInput::convert_charpointer_to_ulong(const char* arg) const +{ + unsigned long int result = 0; + errno = 0; + + if (arg) + { + // man strtoul: + // ... + // The string must begin with an arbitrary amount of white space (as determined by isspace(3)) + // followed by a single optional '+' or '-' sign. If base is zero or 16, the string may then + // include a '0x' prefix, and the number will be read in base 16; otherwise, a zero base is + // taken as 10 (decimal) unless the next character is '0', in which case it is taken as 8 + // (octal). + static int base_magic(0); + + result = ::strtoul(arg, 0, base_magic); + + if (errno) + { + logger.warn() << "convert_charpointer_to_ulong: unable to convert arg '%s' to int; errno: '%s' ", + arg, ::strerror(errno); + result = 0; + } + else + LOG_TRACE(logger) << "convert_charpointer_to_ulong: converted arg '%s' to %ld", arg, result; + + } + else + logger.warn() << "convert_charpointer_to_ulong: got null pointer for arg conversion"; + + return result; +} + + +std::string +av::daemon::HIDInput::stationPairToString(unsigned short kind, unsigned short index) const +{ + std::ostringstream out_stream; + + switch (kind) + { + case KIND_BUTTON: + out_stream << "Button[" << index << "]" << std::ends; + break; + case KIND_VALUE: + out_stream << "Value[" << index << "]" << std::ends; + break; + default: + out_stream << "INVALID_KIND[" << index << "]" << std::ends; + break; + } + return out_stream.str(); +} + +std::string +av::daemon::HIDInput::eventPairToString(unsigned short eventType, unsigned short eventCode) const +{ + unsigned short type (eventType); + unsigned short code (eventCode); + std::string capability (""); + std::string type_s (""); + std::ostringstream codestrbuf; + + // more verbose output + codestrbuf << "[code=" + << std::setw(3) << std::setfill('0') << std::dec << code << "/0x" + << std::setw(3) << std::setfill('0') << std::hex << code << "]" + << std::ends; + + switch (type) { + case EV_KEY: + type_s = "EV_KEY"; + + switch (code) { + case KEY_RESERVED: capability += "(Reserved)"; break; + case KEY_ESC: capability += "(Escape)"; break; + case KEY_1: capability += "(1)"; break; + case KEY_2: capability += "(2)"; break; + case KEY_3: capability += "(3)"; break; + case KEY_4: capability += "(4)"; break; + case KEY_5: capability += "(5)"; break; + case KEY_6: capability += "(6)"; break; + case KEY_7: capability += "(7)"; break; + case KEY_8: capability += "(8)"; break; + case KEY_9: capability += "(9)"; break; + case KEY_0: capability += "(0)"; break; + case KEY_MINUS: capability += "(-)"; break; + case KEY_EQUAL: capability += "(=)"; break; + case KEY_BACKSPACE: capability += "(Backspace)"; break; + case KEY_TAB: capability += "(Tab)"; break; + case KEY_Q: capability += "(Q)"; break; + case KEY_W: capability += "(W)"; break; + case KEY_E: capability += "(E)"; break; + case KEY_R: capability += "(R)"; break; + case KEY_T: capability += "(T)"; break; + case KEY_Y: capability += "(Y)"; break; + case KEY_U: capability += "(U)"; break; + case KEY_I: capability += "(I)"; break; + case KEY_O: capability += "(O)"; break; + case KEY_P: capability += "(P)"; break; + case KEY_LEFTBRACE: capability += "([)"; break; + case KEY_RIGHTBRACE: capability += "(])"; break; + case KEY_ENTER: capability += "(Enter)"; break; + case KEY_LEFTCTRL: capability += "(Ctrl Left)"; break; + case KEY_A: capability += "(A)"; break; + case KEY_S: capability += "(S)"; break; + case KEY_D: capability += "(D)"; break; + case KEY_F: capability += "(F)"; break; + case KEY_G: capability += "(G)"; break; + case KEY_H: capability += "(H)"; break; + case KEY_J: capability += "(J)"; break; + case KEY_K: capability += "(K)"; break; + case KEY_L: capability += "(L)"; break; + case KEY_SEMICOLON: capability += "(;)"; break; + case KEY_APOSTROPHE: capability += "(')"; break; + case KEY_GRAVE: capability += "(`)"; break; + case KEY_LEFTSHIFT: capability += "(Shift Left)"; break; + case KEY_BACKSLASH: capability += "(\\)"; break; + case KEY_Z: capability += "(Z)"; break; + case KEY_X: capability += "(X)"; break; + case KEY_C: capability += "(C)"; break; + case KEY_V: capability += "(V)"; break; + case KEY_B: capability += "(B)"; break; + case KEY_N: capability += "(N)"; break; + case KEY_M: capability += "(M)"; break; + case KEY_COMMA: capability += "(,)"; break; + case KEY_DOT: capability += "(.)"; break; + case KEY_SLASH: capability += "(/)"; break; + case KEY_RIGHTSHIFT: capability += "(Shift Right)"; break; + case KEY_KPASTERISK: capability += "(*)"; break; + case KEY_LEFTALT: capability += "(Alt Left)"; break; + case KEY_SPACE: capability += "(Space)"; break; + case KEY_CAPSLOCK: capability += "(CapsLock)"; break; + case KEY_F1: capability += "(F1)"; break; + case KEY_F2: capability += "(F2)"; break; + case KEY_F3: capability += "(F3)"; break; + case KEY_F4: capability += "(F4)"; break; + case KEY_F5: capability += "(F5)"; break; + case KEY_F6: capability += "(F6)"; break; + case KEY_F7: capability += "(F7)"; break; + case KEY_F8: capability += "(F8)"; break; + case KEY_F9: capability += "(F9)"; break; + case KEY_F10: capability += "(F10)"; break; + case KEY_NUMLOCK: capability += "(NumLock)"; break; + case KEY_SCROLLLOCK: capability += "(ScrollLock)"; break; + case KEY_KP7: capability += "(KeyPad 7)"; break; + case KEY_KP8: capability += "(KeyPad 8)"; break; + case KEY_KP9: capability += "(Keypad 9)"; break; + case KEY_KPMINUS: capability += "(KeyPad Minus)"; break; + case KEY_KP4: capability += "(KeyPad 4)"; break; + case KEY_KP5: capability += "(KeyPad 5)"; break; + case KEY_KP6: capability += "(KeyPad 6)"; break; + case KEY_KPPLUS: capability += "(KeyPad Plus)"; break; + case KEY_KP1: capability += "(KeyPad 1)"; break; + case KEY_KP2: capability += "(KeyPad 2)"; break; + case KEY_KP3: capability += "(KeyPad 3)"; break; + case KEY_KPDOT: capability += "(KeyPad decimal point)"; break; +#if defined(KEY_103RD) + case KEY_103RD: capability += "(KEY_103RD)"; break; +#endif + case KEY_F13: capability += "(F13)"; break; + case KEY_102ND: capability += "(KEY_102ND)"; break; + case KEY_F11: capability += "(F11)"; break; + case KEY_F12: capability += "(F12)"; break; + case KEY_F14: capability += "(F14)"; break; + case KEY_F15: capability += "(F15)"; break; + case KEY_F16: capability += "(F16)"; break; + case KEY_F17: capability += "(F17)"; break; + case KEY_F18: capability += "(F18)"; break; + case KEY_F19: capability += "(F19)"; break; + case KEY_F20: capability += "(F20)"; break; + case KEY_KPENTER: capability += "(Keypad Enter)"; break; + case KEY_RIGHTCTRL: capability += "(Ctrl Right)"; break; + case KEY_KPSLASH: capability += "(KeyPad Forward Slash)"; break; + case KEY_SYSRQ: capability += "(System Request)"; break; + case KEY_RIGHTALT: capability += "(Alt Right)"; break; + case KEY_LINEFEED: capability += "(Line Feed)"; break; + case KEY_HOME: capability += "(Home)"; break; + case KEY_UP: capability += "(Up)"; break; + case KEY_PAGEUP: capability += "(Page Up)"; break; + case KEY_LEFT: capability += "(Left)"; break; + case KEY_RIGHT: capability += "(Right)"; break; + case KEY_END: capability += "(End)"; break; + case KEY_DOWN: capability += "(Down)"; break; + case KEY_PAGEDOWN: capability += "(Page Down)"; break; + case KEY_INSERT: capability += "(Insert)"; break; + case KEY_DELETE: capability += "(Delete)"; break; + case KEY_MACRO: capability += "(Macro)"; break; + case KEY_MUTE: capability += "(Mute)"; break; + case KEY_VOLUMEDOWN: capability += "(Volume Down)"; break; + case KEY_VOLUMEUP: capability += "(Volume Up)"; break; + case KEY_POWER: capability += "(Power)"; break; + case KEY_KPEQUAL: capability += "(KeyPad Equal)"; break; + case KEY_KPPLUSMINUS: capability += "(KeyPad +/-)"; break; + case KEY_PAUSE: capability += "(Pause)"; break; + case KEY_F21: capability += "(F21)"; break; + case KEY_F22: capability += "(F22)"; break; + case KEY_F23: capability += "(F23)"; break; + case KEY_F24: capability += "(F24)"; break; + case KEY_KPCOMMA: capability += "(KeyPad comma)"; break; + case KEY_LEFTMETA: capability += "(Meta Left)"; break; + case KEY_RIGHTMETA: capability += "(Meta Left)"; break; + case KEY_COMPOSE: capability += "(Compose)"; break; + case KEY_STOP: capability += "(Stop)"; break; + case KEY_AGAIN: capability += "(Again)"; break; + case KEY_PROPS: capability += "(Properties)"; break; + case KEY_UNDO: capability += "(Undo)"; break; + case KEY_FRONT: capability += "(Front)"; break; + case KEY_COPY: capability += "(Copy)"; break; + case KEY_OPEN: capability += "(Open)"; break; + case KEY_PASTE: capability += "(Paste)"; break; + case KEY_FIND: capability += "(Find)"; break; + case KEY_CUT: capability += "(Cut)"; break; + case KEY_HELP: capability += "(Help)"; break; + case KEY_MENU: capability += "(Menu)"; break; + case KEY_CALC: capability += "(Calculator)"; break; + case KEY_SETUP: capability += "(Setup)"; break; + case KEY_SLEEP: capability += "(Sleep)"; break; + case KEY_WAKEUP: capability += "(Wakeup)"; break; + case KEY_FILE: capability += "(File)"; break; + case KEY_SENDFILE: capability += "(Send File)"; break; + case KEY_DELETEFILE: capability += "(Delete File)"; break; + case KEY_XFER: capability += "(Transfer)"; break; + case KEY_PROG1: capability += "(Program 1)"; break; + case KEY_PROG2: capability += "(Program 2)"; break; + case KEY_WWW: capability += "(Web Browser)"; break; + case KEY_MSDOS: capability += "(DOS mode)"; break; + case KEY_COFFEE: capability += "(Coffee)"; break; + case KEY_DIRECTION: capability += "(Direction)"; break; + case KEY_CYCLEWINDOWS: capability += "(Window cycle)"; break; + case KEY_MAIL: capability += "(Mail)"; break; + case KEY_BOOKMARKS: capability += "(Book Marks)"; break; + case KEY_COMPUTER: capability += "(Computer)"; break; + case KEY_BACK: capability += "(Back)"; break; + case KEY_FORWARD: capability += "(Forward)"; break; + case KEY_CLOSECD: capability += "(Close CD)"; break; + case KEY_EJECTCD: capability += "(Eject CD)"; break; + case KEY_EJECTCLOSECD: capability += "(Eject / Close CD)"; break; + case KEY_NEXTSONG: capability += "(Next Song)"; break; + case KEY_PLAYPAUSE: capability += "(Play and Pause)"; break; + case KEY_PREVIOUSSONG: capability += "(Previous Song)"; break; + case KEY_STOPCD: capability += "(Stop CD)"; break; + case KEY_RECORD: capability += "(Record)"; break; + case KEY_REWIND: capability += "(Rewind)"; break; + case KEY_PHONE: capability += "(Phone)"; break; + case KEY_ISO: capability += "(ISO)"; break; + case KEY_CONFIG: capability += "(Config)"; break; + case KEY_HOMEPAGE: capability += "(Home)"; break; + case KEY_REFRESH: capability += "(Refresh)"; break; + case KEY_EXIT: capability += "(Exit)"; break; + case KEY_MOVE: capability += "(Move)"; break; + case KEY_EDIT: capability += "(Edit)"; break; + case KEY_SCROLLUP: capability += "(Scroll Up)"; break; + case KEY_SCROLLDOWN: capability += "(Scroll Down)"; break; + case KEY_KPLEFTPAREN: capability += "(KeyPad Parenthesis Left)"; break; + case KEY_KPRIGHTPAREN: capability += "(KeyPad Parenthesis Right)"; break; +#if defined(KEY_INTL1) + case KEY_INTL1: capability += "(Intl 1)"; break; + case KEY_INTL2: capability += "(Intl 2)"; break; + case KEY_INTL3: capability += "(Intl 3)"; break; + case KEY_INTL4: capability += "(Intl 4)"; break; + case KEY_INTL5: capability += "(Intl 5)"; break; + case KEY_INTL6: capability += "(Intl 6)"; break; + case KEY_INTL7: capability += "(Intl 7)"; break; + case KEY_INTL8: capability += "(Intl 8)"; break; + case KEY_INTL9: capability += "(Intl 9)"; break; +#endif +#if defined(KEY_LANG1) + case KEY_LANG1: capability += "(Language 1)"; break; + case KEY_LANG2: capability += "(Language 2)"; break; + case KEY_LANG3: capability += "(Language 3)"; break; + case KEY_LANG4: capability += "(Language 4)"; break; + case KEY_LANG5: capability += "(Language 5)"; break; + case KEY_LANG6: capability += "(Language 6)"; break; + case KEY_LANG7: capability += "(Language 7)"; break; + case KEY_LANG8: capability += "(Language 8)"; break; + case KEY_LANG9: capability += "(Language 9)"; break; +#endif + case KEY_PLAYCD: capability += "(Play CD)"; break; + case KEY_PAUSECD: capability += "(Pause CD)"; break; + case KEY_PROG3: capability += "(Program 3)"; break; + case KEY_PROG4: capability += "(Program 4)"; break; + case KEY_SUSPEND: capability += "(Suspend)"; break; + case KEY_CLOSE: capability += "(Close)"; break; + case KEY_UNKNOWN: capability += "(Specifically unknown)"; break; +#if defined(KEY_BRIGHTNESSDOWN) + case KEY_BRIGHTNESSDOWN: capability += "(Brightness Down)"; break; +#endif +#if defined(KEY_BRIGHTNESSUP) + case KEY_BRIGHTNESSUP: capability += "(Brightness Up)"; break; +#endif + case BTN_0: capability += "(Button 0)"; break; + case BTN_1: capability += "(Button 1)"; break; + case BTN_2: capability += "(Button 2)"; break; + case BTN_3: capability += "(Button 3)"; break; + case BTN_4: capability += "(Button 4)"; break; + case BTN_5: capability += "(Button 5)"; break; + case BTN_6: capability += "(Button 6)"; break; + case BTN_7: capability += "(Button 7)"; break; + case BTN_8: capability += "(Button 8)"; break; + case BTN_9: capability += "(Button 9)"; break; + case BTN_LEFT: capability += "(Left Button)"; break; + case BTN_RIGHT: capability += "(Right Button)"; break; + case BTN_MIDDLE: capability += "(Middle Button)"; break; + case BTN_SIDE: capability += "(Side Button)"; break; + case BTN_EXTRA: capability += "(Extra Button)"; break; + case BTN_FORWARD: capability += "(Forward Button)"; break; + case BTN_BACK: capability += "(Back Button)"; break; + case BTN_TRIGGER: capability += "(Trigger Button)"; break; + case BTN_THUMB: capability += "(Thumb Button)"; break; + case BTN_THUMB2: capability += "(2nd Thumb Button)"; break; + case BTN_TOP: capability += "(Top Button)"; break; + case BTN_TOP2: capability += "(2nd Top Button)"; break; + case BTN_PINKIE: capability += "(Pinkie Button)"; break; + case BTN_BASE: capability += "(Base Button)"; break; + case BTN_BASE2: capability += "(2nd Base Button)"; break; + case BTN_BASE3: capability += "(3rd Base Button)"; break; + case BTN_BASE4: capability += "(4th Base Button)"; break; + case BTN_BASE5: capability += "(5th Base Button)"; break; + case BTN_BASE6: capability += "(6th Base Button)"; break; + case BTN_DEAD: capability += "(Dead Button)"; break; + case BTN_A: capability += "(Button A)"; break; + case BTN_B: capability += "(Button B)"; break; + case BTN_C: capability += "(Button C)"; break; + case BTN_X: capability += "(Button X)"; break; + case BTN_Y: capability += "(Button Y)"; break; + case BTN_Z: capability += "(Button Z)"; break; + case BTN_TL: capability += "(Thumb Left Button)"; break; + case BTN_TR: capability += "(Thumb Right Button )"; break; + case BTN_TL2: capability += "(2nd Thumb Left Button)"; break; + case BTN_TR2: capability += "(2nd Thumb Right Button )"; break; + case BTN_SELECT: capability += "(Select Button)"; break; + case BTN_MODE: capability += "(Mode Button)"; break; + case BTN_THUMBL: capability += "(Another Left Thumb Button )"; break; + case BTN_THUMBR: capability += "(Another Right Thumb Button )"; break; + case BTN_TOOL_PEN: capability += "(Digitiser Pen Tool)"; break; + case BTN_TOOL_RUBBER: capability += "(Digitiser Rubber Tool)"; break; + case BTN_TOOL_BRUSH: capability += "(Digitiser Brush Tool)"; break; + case BTN_TOOL_PENCIL: capability += "(Digitiser Pencil Tool)"; break; + case BTN_TOOL_AIRBRUSH: capability += "(Digitiser Airbrush Tool)"; break; + case BTN_TOOL_FINGER: capability += "(Digitiser Finger Tool)"; break; + case BTN_TOOL_MOUSE: capability += "(Digitiser Mouse Tool)"; break; + case BTN_TOOL_LENS: capability += "(Digitiser Lens Tool)"; break; + case BTN_TOUCH: capability += "(Digitiser Touch Button)"; break; + case BTN_STYLUS: capability += "(Digitiser Stylus Button)"; break; + case BTN_STYLUS2: capability += "(Second Digitiser Stylus Button)"; break; + default: capability += "(Unknown Key)"; break; + } + break; + case EV_REL: + type_s = "EV_REL"; + + switch (code) { + case REL_X: capability += "(X Axis)"; break; + case REL_Y: capability += "(Y Axis)"; break; + case REL_Z: capability += "(Z Axis)"; break; + case REL_HWHEEL: capability += "(Horizontal Wheel)"; break; + case REL_DIAL: capability += "(Dial)"; break; + case REL_WHEEL: capability += "(Vertical Wheel)"; break; + case REL_MISC: capability += "(Miscellaneous)"; break; + default: capability += "(Unknown relative feature)"; break; + } + break; + case EV_ABS: + type_s = "EV_ABS"; + + switch (code) { + case ABS_X: capability += "(X Axis)"; break; + case ABS_Y: capability += "(Y Axis)"; break; + case ABS_Z: capability += "(Z Axis)"; break; + case ABS_RX: capability += "(X Rate Axis)"; break; + case ABS_RY: capability += "(Y Rate Axis)"; break; + case ABS_RZ: capability += "(Z Rate Axis)"; break; + case ABS_THROTTLE: capability += "(Throttle)"; break; + case ABS_RUDDER: capability += "(Rudder)"; break; + case ABS_WHEEL: capability += "(Wheel)"; break; + case ABS_GAS: capability += "(Accelerator)"; break; + case ABS_BRAKE: capability += "(Brake)"; break; + case ABS_HAT0X: capability += "(Hat zero, x axis)"; break; + case ABS_HAT0Y: capability += "(Hat zero, y axis)"; break; + case ABS_HAT1X: capability += "(Hat one, x axis)"; break; + case ABS_HAT1Y: capability += "(Hat one, y axis)"; break; + case ABS_HAT2X: capability += "(Hat two, x axis)"; break; + case ABS_HAT2Y: capability += "(Hat two, y axis)"; break; + case ABS_HAT3X: capability += "(Hat three, x axis)"; break; + case ABS_HAT3Y: capability += "(Hat three, y axis)"; break; + case ABS_PRESSURE: capability += "(Pressure)"; break; + case ABS_DISTANCE: capability += "(Distance)"; break; + case ABS_TILT_X: capability += "(Tilt, X axis)"; break; + case ABS_TILT_Y: capability += "(Tilt, Y axis)"; break; + case ABS_MISC: capability += "(Miscellaneous)"; break; + default: capability += "(Unknown absolute feature)"; break; + } + break; + case EV_MSC: + type_s = "EV_MSC"; + break; + case EV_LED: + type_s = "EV_LED"; + + switch (code) { + case LED_NUML: capability += "(Num Lock)"; break; + case LED_CAPSL: capability += "(Caps Lock)"; break; + case LED_SCROLLL: capability += "(Scroll Lock)"; break; + case LED_COMPOSE: capability += "(Compose)"; break; + case LED_KANA: capability += "(Kana)"; break; + case LED_SLEEP: capability += "(Sleep)"; break; + case LED_SUSPEND: capability += "(Suspend)"; break; + case LED_MISC: capability += "(Miscellaneous)"; break; + case LED_MUTE: capability += "(Mute)"; break; +#if defined(LED_MAIL) + case LED_MAIL: capability += "(Mail)"; break; +#endif +#if defined(LED_CHARGING) + case LED_CHARGING: capability += "(Charging)"; break; +#endif + case LED_MAX: capability += "(Max)"; break; + default: capability += "(Unknown LED type)"; break; + } + break; + case EV_SND: + type_s = "EV_SND"; + break; + case EV_REP: + type_s = "EV_REP"; + break; + case EV_FF: + type_s = "EV_FF"; + break; + default: + type_s = "UNKNOWN_EVENT_TYPE"; + break; + } + + return (type_s + "::" + capability + codestrbuf.str()); +} + +bool +av::daemon::HIDInput::scanUnsignedInteger(const std::string& int_string, unsigned int& return_value) const +{ + if (int_string.empty()) return false; + +#if 0 + // stringstream broken on linux; do not use! + std::stringstream read_stream(int_string); + + if (int_string.size() > 0 && int_string[0] == '0') { + // hex or octal + if (int_string.size() > 1 && (int_string[1] == 'x' || int_string[1] == 'X')) { + // hex + read_stream >> std::hex >> return_value; + return !read_stream.fail(); + } else { + // octal + read_stream >> std::oct >> r23eturn_value; + return !read_stream.fail(); + } + } else { + // decimal + read_stream >> return_value; + return !read_stream.fail(); + } +#else + // return_value = ::strtoul(int_string.c_str(), 0, 0); + return_value = convert_charpointer_to_ulong(int_string.c_str()); + + return true; +#endif +} + +bool +av::daemon::HIDInput::scanInteger(const std::string& int_string, int& return_value) const +{ + if (int_string.empty()) return false; + + return_value = ::strtol(int_string.c_str(), 0, 0); + return true; +} + +bool +av::daemon::HIDInput::stationLooksForEvent(int station_index, const struct input_event& event) const +{ + unsigned int type_code_packed = pack_into_uint(event.type, event.code); + const HIDMapping& hidmapping = getStationHIDMapping(station_index); + + logger.trace() << "readLoop: event pair: " << type_code_packed << " found-el: " << hidmapping.count(type_code_packed); + return hidmapping.find(type_code_packed)!= hidmapping.end(); +} + +const av::daemon::HIDInput::HIDMapping& +av::daemon::HIDInput::getStationHIDMapping(int station_index) const +{ + StationHIDMappingLookup::const_iterator iter = mStationHIDMappingLookup.find(station_index); + if (iter == mStationHIDMappingLookup.end()) + return mDefaultHIDMapping; + + return (*iter).second; +} + +float +av::daemon::HIDInput::normalizeAbsValue(const input_event& event) const +{ + float normalized_value = event.value; + + HIDInput::AbsInfoMap::const_iterator iter (mAbsInfoMap.find(event.code)); + + if (iter != mAbsInfoMap.end()) + { + const input_absinfo& info = (*iter).second; + // from /usr/src/linux/drivers/input/joydev.c + int c0 = (info.maximum + info.minimum) / 2 - info.flat; + int c1 = (info.maximum + info.minimum) / 2 + info.flat; + int t = (info.maximum - info.minimum) / 2 - 2 * info.flat; + + if (t == 0) + { + logger.warn() << "readLoop: EV_ABS illegal ABS_INFO (t==0!)"; + // leave value untouched + } + else + { + int c2 = (1 << 29) / t; + int val_i = event.value; + + val_i = val_i > c0 ? + (val_i < c1 ? 0 : ((c2 * (val_i - c1)) >> 14)) : + ((c2 * (val_i - c0)) >> 14); + + // value = 2.0f * (value - (float)info.minimum) / + // (float) (info.maximum - info.minimum) - 1.0f; + normalized_value = val_i / 32767.0f; + if (normalized_value < -1.0f) + normalized_value = -1.0f; + else if (normalized_value > 1.0f) + normalized_value = 1.0f; + } + } + + return normalized_value; +} + +void +av::daemon::HIDInput::printMaps() const +{ + logger.info() << "printMaps: HID->StationSegment Default map:"; + NumStationMap::const_iterator ns; + + for (ns = mStations.begin(); ns != mStations.end(); ++ns) + { + int station_index = (*ns).first; + Station* station = (*ns).second; + + logger.info() << "printMaps: HID->StationSegment of station " << station_index + << " '" << station->getName() << "'"; + + StationHIDMappingLookup::const_iterator iter = mStationHIDMappingLookup.find(station_index); + + if (iter != mStationHIDMappingLookup.end()) + printHIDMapping((*iter).second); + else + logger.warn() << "printMaps: Can't find HIDMapping!"; + } +} + +void +av::daemon::HIDInput::applyEventToStation(int station_index, const input_event& event) +{ + HIDMapping::const_iterator matching_hid_entry = + getStationHIDMapping(station_index).find(pack_into_uint(event.type, event.code)); + if (matching_hid_entry == getStationHIDMapping(station_index).end()) + return; + + unsigned int kind_index_pair = matching_hid_entry->second; + unsigned short kind=0; + unsigned short index=0; + unpack_from_uint(kind_index_pair,kind,index); + + NumStationMap::iterator station_iter = mStations.find(station_index); + if (station_iter == mStations.end()) + return; + + Station* station = station_iter->second; + + // leave this in for debugging + logger.trace() << "applyEventToStation: station %d ('%s'): mapping '%s' (%d) -> '%s' ('%d::%d' -> '%d::%d')", + station_index, station->getName(), + eventPairToString(event.type, event.code).c_str(), event.value, + stationPairToString(kind, index).c_str(), + event.type, event.code, kind, index; + + switch (kind) + { + case KIND_BUTTON: + station->setButton(index, event.value); + logger.trace() << "applyEventToStation: current button of %d: %d", index, station->getButton(index); + break; + case KIND_VALUE: + // if this is an EV_REL event and _accumRel is true we accumlate value in the station + if (mAccumRel && event.type == EV_REL) + station->setValue(index,event.value+station->getValue(index)); + else if (mNormAbs && event.type == EV_ABS) + station->setValue(index, normalizeAbsValue(event)); + else + station->setValue(index,event.value); + logger.trace() << "applyEventToStation: current value of %d: %f", index, station->getValue(index); + break; + default: + logger.fatal() << "applyEventToStation: unknown kind in mapping '%s' for station '%s' (#%d)!", + eventPairToString(event.type, event.code).c_str(), + station->getName(), + station_index; + break; + } +} + +void +av::daemon::HIDInput::clearRelativeStationValues() +{ + for (NumStationMap::iterator ns = mStations.begin(); ns != mStations.end(); ++ns) + { + int station_index = (*ns).first; + Station* station = (*ns).second; + const HIDMapping& hidmapping = getStationHIDMapping(station_index); + unsigned short evType; + unsigned short evCode; + unsigned short kind; + unsigned short index; + + for (HIDMapping::const_iterator hidmapping_iter = hidmapping.begin(); + hidmapping_iter != hidmapping.end(); + ++hidmapping_iter) + { + unpack_from_uint(hidmapping_iter->first, evType, evCode); + unpack_from_uint(hidmapping_iter->second, kind, index); + + if (kind == KIND_VALUE && evType == EV_REL && 0.0 != station->getValue(index)) + { + logger.trace() << "clearRelativeStationValues: resetting current value of %d (%f) to 0.0", + index, station->getValue(index); + station->setValue(index, 0.0); + } + if (kind == KIND_BUTTON && evType == EV_REL && 0 != station->getButton(index)) + { + logger.debug() << "clearRelativeStationValues: resetting current value of %d (%d) to 0", + index, station->getButton(index); + station->setButton(index, 0); + } + } + } +} + +/* virtual */ void +av::daemon::HIDInput::updateLED(unsigned short eventCode, bool on) +{ + struct input_event event; + + event.type = EV_LED; + event.code = eventCode; + event.value = on; + + writeEvent(event); +} + +/* virtual */ void +av::daemon::HIDInput::updateLEDs(bool force) +{ + LastLEDStateLookup::iterator iter = mLastLEDStateLookup.begin(); + LastLEDStateLookup::iterator end = mLastLEDStateLookup.end(); + while (iter != end) + { + Station *station = iter->first; + int station_id = -1; + + NumStationMap::const_iterator ns_iter = mStations.begin(); + NumStationMap::const_iterator ns_end = mStations.end(); + while (ns_iter != ns_end) + { + if (ns_iter->second == station) + { + station_id = ns_iter->first; + break; + } + ++ns_iter; + } + + for (size_t led=0; ledsecond.size(); ++led) + { + if ((station->getLED(led) != iter->second[led]) || force) + { + unsigned int stationPair = pack_into_uint(KIND_LED, led); + StationHIDLEDMappingLookup::iterator sthm_iter = mStationHIDLEDMappingLookup.find(station_id); + if (sthm_iter != mStationHIDLEDMappingLookup.end()) + { + HIDLEDMapping& hidmapping = sthm_iter->second; + HIDLEDMapping::iterator hm_iter = hidmapping.find(stationPair); + if (hm_iter != hidmapping.end()) + { + unsigned short eventType; + unsigned short eventCode; + unpack_from_uint(hm_iter->second, eventType, eventCode); + assert(eventType == EV_LED); + updateLED(eventCode, station->getLED(led)); + logger.trace() << "updateLEDs: updated LED state '%s'", eventCode; + } + } + } + } + iter->second = station->getLEDs(); + ++iter; + } +} + +/* virtual */ void +av::daemon::HIDInput::startLEDs() +{ + for (int i=0; i<=LED_MAX; ++i) + updateLED(i, false); + + updateLEDs(true); +} + +/* virtual */ void +av::daemon::HIDInput::stopLEDs() +{ + for (int i=0; i<=LED_MAX; ++i) + updateLED(i, false); +} diff --git a/avango-daemon/src/avango/daemon/Init.cpp b/avango-daemon/src/avango/daemon/Init.cpp new file mode 100644 index 00000000..900a9d05 --- /dev/null +++ b/avango-daemon/src/avango/daemon/Init.cpp @@ -0,0 +1,75 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef VRPN_SUPPORT +#include +#endif + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::Init")); +} + +AV_TYPED_DEFINE_ABSTRACT(av::daemon::Init); + +/* static */ void +av::daemon::Init::initClass() +{ + if (!isTypeInitialized()) + { + av::daemon::Device::initClass(); + av::daemon::DeviceActuator::initClass(); + av::daemon::DeviceDaemon::initClass(); + av::daemon::DeviceSensor::initClass(); + av::daemon::DeviceService::initClass(); + av::daemon::DTrack::initClass(); + av::daemon::HIDInput::initClass(); + av::daemon::WacomTablet::initClass(); + av::daemon::Wiimote::initClass(); + av::daemon::WiimoteActuator::initClass(); + +#ifdef VRPN_SUPPORT + av::daemon::VRPNClient::initClass(); +#endif + + AV_TYPED_INIT_ABSTRACT(av::Type::badType(), "av::daemon::Init", true); + } +} diff --git a/avango-daemon/src/avango/daemon/LinuxEvent.cpp b/avango-daemon/src/avango/daemon/LinuxEvent.cpp new file mode 100644 index 00000000..69e41ba9 --- /dev/null +++ b/avango-daemon/src/avango/daemon/LinuxEvent.cpp @@ -0,0 +1,520 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +namespace +{ + static const av::daemon::LinuxEvent sEventMap; +} + +av::daemon::LinuxEvent::LinuxEvent() +{ + // own definitions + insert(std::make_pair("STATION_BUTTON", 0x00)); + insert(std::make_pair("STATION_VALUE", 0x01)); + insert(std::make_pair("STATION_LED", 0x02)); + + // definitions from /usr/include/linux/input.h + insert(std::make_pair("EV_SYN", 0x00)); + insert(std::make_pair("EV_KEY", 0x01)); + insert(std::make_pair("EV_REL", 0x02)); + insert(std::make_pair("EV_ABS", 0x03)); + insert(std::make_pair("EV_MSC", 0x04)); + insert(std::make_pair("EV_SW", 0x05)); + insert(std::make_pair("EV_LED", 0x11)); + insert(std::make_pair("EV_SND", 0x12)); + insert(std::make_pair("EV_REP", 0x14)); + insert(std::make_pair("EV_FF", 0x15)); + insert(std::make_pair("EV_PWR", 0x16)); + insert(std::make_pair("EV_FF_STATUS", 0x17)); + insert(std::make_pair("EV_MAX", 0x1f)); + insert(std::make_pair("SYN_REPORT", 0)); + insert(std::make_pair("SYN_CONFIG", 1)); + insert(std::make_pair("KEY_RESERVED", 0)); + insert(std::make_pair("KEY_ESC", 1)); + insert(std::make_pair("KEY_1", 2)); + insert(std::make_pair("KEY_2", 3)); + insert(std::make_pair("KEY_3", 4)); + insert(std::make_pair("KEY_4", 5)); + insert(std::make_pair("KEY_5", 6)); + insert(std::make_pair("KEY_6", 7)); + insert(std::make_pair("KEY_7", 8)); + insert(std::make_pair("KEY_8", 9)); + insert(std::make_pair("KEY_9", 10)); + insert(std::make_pair("KEY_0", 11)); + insert(std::make_pair("KEY_MINUS", 12)); + insert(std::make_pair("KEY_EQUAL", 13)); + insert(std::make_pair("KEY_BACKSPACE", 14)); + insert(std::make_pair("KEY_TAB", 15)); + insert(std::make_pair("KEY_Q", 16)); + insert(std::make_pair("KEY_W", 17)); + insert(std::make_pair("KEY_E", 18)); + insert(std::make_pair("KEY_R", 19)); + insert(std::make_pair("KEY_T", 20)); + insert(std::make_pair("KEY_Y", 21)); + insert(std::make_pair("KEY_U", 22)); + insert(std::make_pair("KEY_I", 23)); + insert(std::make_pair("KEY_O", 24)); + insert(std::make_pair("KEY_P", 25)); + insert(std::make_pair("KEY_LEFTBRACE", 26)); + insert(std::make_pair("KEY_RIGHTBRACE", 27)); + insert(std::make_pair("KEY_ENTER", 28)); + insert(std::make_pair("KEY_LEFTCTRL", 29)); + insert(std::make_pair("KEY_A", 30)); + insert(std::make_pair("KEY_S", 31)); + insert(std::make_pair("KEY_D", 32)); + insert(std::make_pair("KEY_F", 33)); + insert(std::make_pair("KEY_G", 34)); + insert(std::make_pair("KEY_H", 35)); + insert(std::make_pair("KEY_J", 36)); + insert(std::make_pair("KEY_K", 37)); + insert(std::make_pair("KEY_L", 38)); + insert(std::make_pair("KEY_SEMICOLON", 39)); + insert(std::make_pair("KEY_APOSTROPHE", 40)); + insert(std::make_pair("KEY_GRAVE", 41)); + insert(std::make_pair("KEY_LEFTSHIFT", 42)); + insert(std::make_pair("KEY_BACKSLASH", 43)); + insert(std::make_pair("KEY_Z", 44)); + insert(std::make_pair("KEY_X", 45)); + insert(std::make_pair("KEY_C", 46)); + insert(std::make_pair("KEY_V", 47)); + insert(std::make_pair("KEY_B", 48)); + insert(std::make_pair("KEY_N", 49)); + insert(std::make_pair("KEY_M", 50)); + insert(std::make_pair("KEY_COMMA", 51)); + insert(std::make_pair("KEY_DOT", 52)); + insert(std::make_pair("KEY_SLASH", 53)); + insert(std::make_pair("KEY_RIGHTSHIFT", 54)); + insert(std::make_pair("KEY_KPASTERISK", 55)); + insert(std::make_pair("KEY_LEFTALT", 56)); + insert(std::make_pair("KEY_SPACE", 57)); + insert(std::make_pair("KEY_CAPSLOCK", 58)); + insert(std::make_pair("KEY_F1", 59)); + insert(std::make_pair("KEY_F2", 60)); + insert(std::make_pair("KEY_F3", 61)); + insert(std::make_pair("KEY_F4", 62)); + insert(std::make_pair("KEY_F5", 63)); + insert(std::make_pair("KEY_F6", 64)); + insert(std::make_pair("KEY_F7", 65)); + insert(std::make_pair("KEY_F8", 66)); + insert(std::make_pair("KEY_F9", 67)); + insert(std::make_pair("KEY_F10", 68)); + insert(std::make_pair("KEY_NUMLOCK", 69)); + insert(std::make_pair("KEY_SCROLLLOCK", 70)); + insert(std::make_pair("KEY_KP7", 71)); + insert(std::make_pair("KEY_KP8", 72)); + insert(std::make_pair("KEY_KP9", 73)); + insert(std::make_pair("KEY_KPMINUS", 74)); + insert(std::make_pair("KEY_KP4", 75)); + insert(std::make_pair("KEY_KP5", 76)); + insert(std::make_pair("KEY_KP6", 77)); + insert(std::make_pair("KEY_KPPLUS", 78)); + insert(std::make_pair("KEY_KP1", 79)); + insert(std::make_pair("KEY_KP2", 80)); + insert(std::make_pair("KEY_KP3", 81)); + insert(std::make_pair("KEY_KP0", 82)); + insert(std::make_pair("KEY_KPDOT", 83)); + insert(std::make_pair("KEY_ZENKAKUHANKAKU", 85)); + insert(std::make_pair("KEY_102ND", 86)); + insert(std::make_pair("KEY_F11", 87)); + insert(std::make_pair("KEY_F12", 88)); + insert(std::make_pair("KEY_RO", 89)); + insert(std::make_pair("KEY_KATAKANA", 90)); + insert(std::make_pair("KEY_HIRAGANA", 91)); + insert(std::make_pair("KEY_HENKAN", 92)); + insert(std::make_pair("KEY_KATAKANAHIRAGANA", 93)); + insert(std::make_pair("KEY_MUHENKAN", 94)); + insert(std::make_pair("KEY_KPJPCOMMA", 95)); + insert(std::make_pair("KEY_KPENTER", 96)); + insert(std::make_pair("KEY_RIGHTCTRL", 97)); + insert(std::make_pair("KEY_KPSLASH", 98)); + insert(std::make_pair("KEY_SYSRQ", 99)); + insert(std::make_pair("KEY_RIGHTALT", 100)); + insert(std::make_pair("KEY_LINEFEED", 101)); + insert(std::make_pair("KEY_HOME", 102)); + insert(std::make_pair("KEY_UP", 103)); + insert(std::make_pair("KEY_PAGEUP", 104)); + insert(std::make_pair("KEY_LEFT", 105)); + insert(std::make_pair("KEY_RIGHT", 106)); + insert(std::make_pair("KEY_END", 107)); + insert(std::make_pair("KEY_DOWN", 108)); + insert(std::make_pair("KEY_PAGEDOWN", 109)); + insert(std::make_pair("KEY_INSERT", 110)); + insert(std::make_pair("KEY_DELETE", 111)); + insert(std::make_pair("KEY_MACRO", 112)); + insert(std::make_pair("KEY_MUTE", 113)); + insert(std::make_pair("KEY_VOLUMEDOWN", 114)); + insert(std::make_pair("KEY_VOLUMEUP", 115)); + insert(std::make_pair("KEY_POWER", 116)); + insert(std::make_pair("KEY_KPEQUAL", 117)); + insert(std::make_pair("KEY_KPPLUSMINUS", 118)); + insert(std::make_pair("KEY_PAUSE", 119)); + insert(std::make_pair("KEY_KPCOMMA", 121)); + insert(std::make_pair("KEY_HANGEUL", 122)); + //insert(std::make_pair("KEY_HANGUEL", KEY_HANGEUL)); + insert(std::make_pair("KEY_HANJA", 123)); + insert(std::make_pair("KEY_YEN", 124)); + insert(std::make_pair("KEY_LEFTMETA", 125)); + insert(std::make_pair("KEY_RIGHTMETA", 126)); + insert(std::make_pair("KEY_COMPOSE", 127)); + insert(std::make_pair("KEY_STOP", 128)); + insert(std::make_pair("KEY_AGAIN", 129)); + insert(std::make_pair("KEY_PROPS", 130)); + insert(std::make_pair("KEY_UNDO", 131)); + insert(std::make_pair("KEY_FRONT", 132)); + insert(std::make_pair("KEY_COPY", 133)); + insert(std::make_pair("KEY_OPEN", 134)); + insert(std::make_pair("KEY_PASTE", 135)); + insert(std::make_pair("KEY_FIND", 136)); + insert(std::make_pair("KEY_CUT", 137)); + insert(std::make_pair("KEY_HELP", 138)); + insert(std::make_pair("KEY_MENU", 139)); + insert(std::make_pair("KEY_CALC", 140)); + insert(std::make_pair("KEY_SETUP", 141)); + insert(std::make_pair("KEY_SLEEP", 142)); + insert(std::make_pair("KEY_WAKEUP", 143)); + insert(std::make_pair("KEY_FILE", 144)); + insert(std::make_pair("KEY_SENDFILE", 145)); + insert(std::make_pair("KEY_DELETEFILE", 146)); + insert(std::make_pair("KEY_XFER", 147)); + insert(std::make_pair("KEY_PROG1", 148)); + insert(std::make_pair("KEY_PROG2", 149)); + insert(std::make_pair("KEY_WWW", 150)); + insert(std::make_pair("KEY_MSDOS", 151)); + insert(std::make_pair("KEY_COFFEE", 152)); + insert(std::make_pair("KEY_DIRECTION", 153)); + insert(std::make_pair("KEY_CYCLEWINDOWS", 154)); + insert(std::make_pair("KEY_MAIL", 155)); + insert(std::make_pair("KEY_BOOKMARKS", 156)); + insert(std::make_pair("KEY_COMPUTER", 157)); + insert(std::make_pair("KEY_BACK", 158)); + insert(std::make_pair("KEY_FORWARD", 159)); + insert(std::make_pair("KEY_CLOSECD", 160)); + insert(std::make_pair("KEY_EJECTCD", 161)); + insert(std::make_pair("KEY_EJECTCLOSECD", 162)); + insert(std::make_pair("KEY_NEXTSONG", 163)); + insert(std::make_pair("KEY_PLAYPAUSE", 164)); + insert(std::make_pair("KEY_PREVIOUSSONG", 165)); + insert(std::make_pair("KEY_STOPCD", 166)); + insert(std::make_pair("KEY_RECORD", 167)); + insert(std::make_pair("KEY_REWIND", 168)); + insert(std::make_pair("KEY_PHONE", 169)); + insert(std::make_pair("KEY_ISO", 170)); + insert(std::make_pair("KEY_CONFIG", 171)); + insert(std::make_pair("KEY_HOMEPAGE", 172)); + insert(std::make_pair("KEY_REFRESH", 173)); + insert(std::make_pair("KEY_EXIT", 174)); + insert(std::make_pair("KEY_MOVE", 175)); + insert(std::make_pair("KEY_EDIT", 176)); + insert(std::make_pair("KEY_SCROLLUP", 177)); + insert(std::make_pair("KEY_SCROLLDOWN", 178)); + insert(std::make_pair("KEY_KPLEFTPAREN", 179)); + insert(std::make_pair("KEY_KPRIGHTPAREN", 180)); + insert(std::make_pair("KEY_NEW", 181)); + insert(std::make_pair("KEY_REDO", 182)); + insert(std::make_pair("KEY_F13", 183)); + insert(std::make_pair("KEY_F14", 184)); + insert(std::make_pair("KEY_F15", 185)); + insert(std::make_pair("KEY_F16", 186)); + insert(std::make_pair("KEY_F17", 187)); + insert(std::make_pair("KEY_F18", 188)); + insert(std::make_pair("KEY_F19", 189)); + insert(std::make_pair("KEY_F20", 190)); + insert(std::make_pair("KEY_F21", 191)); + insert(std::make_pair("KEY_F22", 192)); + insert(std::make_pair("KEY_F23", 193)); + insert(std::make_pair("KEY_F24", 194)); + insert(std::make_pair("KEY_PLAYCD", 200)); + insert(std::make_pair("KEY_PAUSECD", 201)); + insert(std::make_pair("KEY_PROG3", 202)); + insert(std::make_pair("KEY_PROG4", 203)); + insert(std::make_pair("KEY_SUSPEND", 205)); + insert(std::make_pair("KEY_CLOSE", 206)); + insert(std::make_pair("KEY_PLAY", 207)); + insert(std::make_pair("KEY_FASTFORWARD", 208)); + insert(std::make_pair("KEY_BASSBOOST", 209)); + insert(std::make_pair("KEY_PRINT", 210)); + insert(std::make_pair("KEY_HP", 211)); + insert(std::make_pair("KEY_CAMERA", 212)); + insert(std::make_pair("KEY_SOUND", 213)); + insert(std::make_pair("KEY_QUESTION", 214)); + insert(std::make_pair("KEY_EMAIL", 215)); + insert(std::make_pair("KEY_CHAT", 216)); + insert(std::make_pair("KEY_SEARCH", 217)); + insert(std::make_pair("KEY_CONNECT", 218)); + insert(std::make_pair("KEY_FINANCE", 219)); + insert(std::make_pair("KEY_SPORT", 220)); + insert(std::make_pair("KEY_SHOP", 221)); + insert(std::make_pair("KEY_ALTERASE", 222)); + insert(std::make_pair("KEY_CANCEL", 223)); + insert(std::make_pair("KEY_BRIGHTNESSDOWN", 224)); + insert(std::make_pair("KEY_BRIGHTNESSUP", 225)); + insert(std::make_pair("KEY_MEDIA", 226)); + insert(std::make_pair("KEY_SWITCHVIDEOMODE", 227)); + insert(std::make_pair("KEY_KBDILLUMTOGGLE", 228)); + insert(std::make_pair("KEY_KBDILLUMDOWN", 229)); + insert(std::make_pair("KEY_KBDILLUMUP", 230)); + insert(std::make_pair("KEY_SEND", 231)); + insert(std::make_pair("KEY_REPLY", 232)); + insert(std::make_pair("KEY_FORWARDMAIL", 233)); + insert(std::make_pair("KEY_SAVE", 234)); + insert(std::make_pair("KEY_DOCUMENTS", 235)); + insert(std::make_pair("KEY_BATTERY", 236)); + insert(std::make_pair("KEY_UNKNOWN", 240)); + insert(std::make_pair("BTN_MISC", 0x100)); + insert(std::make_pair("BTN_0", 0x100)); + insert(std::make_pair("BTN_1", 0x101)); + insert(std::make_pair("BTN_2", 0x102)); + insert(std::make_pair("BTN_3", 0x103)); + insert(std::make_pair("BTN_4", 0x104)); + insert(std::make_pair("BTN_5", 0x105)); + insert(std::make_pair("BTN_6", 0x106)); + insert(std::make_pair("BTN_7", 0x107)); + insert(std::make_pair("BTN_8", 0x108)); + insert(std::make_pair("BTN_9", 0x109)); + insert(std::make_pair("BTN_MOUSE", 0x110)); + insert(std::make_pair("BTN_LEFT", 0x110)); + insert(std::make_pair("BTN_RIGHT", 0x111)); + insert(std::make_pair("BTN_MIDDLE", 0x112)); + insert(std::make_pair("BTN_SIDE", 0x113)); + insert(std::make_pair("BTN_EXTRA", 0x114)); + insert(std::make_pair("BTN_FORWARD", 0x115)); + insert(std::make_pair("BTN_BACK", 0x116)); + insert(std::make_pair("BTN_TASK", 0x117)); + insert(std::make_pair("BTN_JOYSTICK", 0x120)); + insert(std::make_pair("BTN_TRIGGER", 0x120)); + insert(std::make_pair("BTN_THUMB", 0x121)); + insert(std::make_pair("BTN_THUMB2", 0x122)); + insert(std::make_pair("BTN_TOP", 0x123)); + insert(std::make_pair("BTN_TOP2", 0x124)); + insert(std::make_pair("BTN_PINKIE", 0x125)); + insert(std::make_pair("BTN_BASE", 0x126)); + insert(std::make_pair("BTN_BASE2", 0x127)); + insert(std::make_pair("BTN_BASE3", 0x128)); + insert(std::make_pair("BTN_BASE4", 0x129)); + insert(std::make_pair("BTN_BASE5", 0x12a)); + insert(std::make_pair("BTN_BASE6", 0x12b)); + insert(std::make_pair("BTN_DEAD", 0x12f)); + insert(std::make_pair("BTN_GAMEPAD", 0x130)); + insert(std::make_pair("BTN_A", 0x130)); + insert(std::make_pair("BTN_B", 0x131)); + insert(std::make_pair("BTN_C", 0x132)); + insert(std::make_pair("BTN_X", 0x133)); + insert(std::make_pair("BTN_Y", 0x134)); + insert(std::make_pair("BTN_Z", 0x135)); + insert(std::make_pair("BTN_TL", 0x136)); + insert(std::make_pair("BTN_TR", 0x137)); + insert(std::make_pair("BTN_TL2", 0x138)); + insert(std::make_pair("BTN_TR2", 0x139)); + insert(std::make_pair("BTN_SELECT", 0x13a)); + insert(std::make_pair("BTN_START", 0x13b)); + insert(std::make_pair("BTN_MODE", 0x13c)); + insert(std::make_pair("BTN_THUMBL", 0x13d)); + insert(std::make_pair("BTN_THUMBR", 0x13e)); + insert(std::make_pair("BTN_DIGI", 0x140)); + insert(std::make_pair("BTN_TOOL_PEN", 0x140)); + insert(std::make_pair("BTN_TOOL_RUBBER", 0x141)); + insert(std::make_pair("BTN_TOOL_BRUSH", 0x142)); + insert(std::make_pair("BTN_TOOL_PENCIL", 0x143)); + insert(std::make_pair("BTN_TOOL_AIRBRUSH", 0x144)); + insert(std::make_pair("BTN_TOOL_FINGER", 0x145)); + insert(std::make_pair("BTN_TOOL_MOUSE", 0x146)); + insert(std::make_pair("BTN_TOOL_LENS", 0x147)); + insert(std::make_pair("BTN_TOUCH", 0x14a)); + insert(std::make_pair("BTN_STYLUS", 0x14b)); + insert(std::make_pair("BTN_STYLUS2", 0x14c)); + insert(std::make_pair("BTN_TOOL_DOUBLETAP", 0x14d)); + insert(std::make_pair("BTN_TOOL_TRIPLETAP", 0x14e)); + insert(std::make_pair("BTN_WHEEL", 0x150)); + insert(std::make_pair("BTN_GEAR_DOWN", 0x150)); + insert(std::make_pair("BTN_GEAR_UP", 0x151)); + insert(std::make_pair("KEY_OK", 0x160)); + insert(std::make_pair("KEY_SELECT", 0x161)); + insert(std::make_pair("KEY_GOTO", 0x162)); + insert(std::make_pair("KEY_CLEAR", 0x163)); + insert(std::make_pair("KEY_POWER2", 0x164)); + insert(std::make_pair("KEY_OPTION", 0x165)); + insert(std::make_pair("KEY_INFO", 0x166)); + insert(std::make_pair("KEY_TIME", 0x167)); + insert(std::make_pair("KEY_VENDOR", 0x168)); + insert(std::make_pair("KEY_ARCHIVE", 0x169)); + insert(std::make_pair("KEY_PROGRAM", 0x16a)); + insert(std::make_pair("KEY_CHANNEL", 0x16b)); + insert(std::make_pair("KEY_FAVORITES", 0x16c)); + insert(std::make_pair("KEY_EPG", 0x16d)); + insert(std::make_pair("KEY_PVR", 0x16e)); + insert(std::make_pair("KEY_MHP", 0x16f)); + insert(std::make_pair("KEY_LANGUAGE", 0x170)); + insert(std::make_pair("KEY_TITLE", 0x171)); + insert(std::make_pair("KEY_SUBTITLE", 0x172)); + insert(std::make_pair("KEY_ANGLE", 0x173)); + insert(std::make_pair("KEY_ZOOM", 0x174)); + insert(std::make_pair("KEY_MODE", 0x175)); + insert(std::make_pair("KEY_KEYBOARD", 0x176)); + insert(std::make_pair("KEY_SCREEN", 0x177)); + insert(std::make_pair("KEY_PC", 0x178)); + insert(std::make_pair("KEY_TV", 0x179)); + insert(std::make_pair("KEY_TV2", 0x17a)); + insert(std::make_pair("KEY_VCR", 0x17b)); + insert(std::make_pair("KEY_VCR2", 0x17c)); + insert(std::make_pair("KEY_SAT", 0x17d)); + insert(std::make_pair("KEY_SAT2", 0x17e)); + insert(std::make_pair("KEY_CD", 0x17f)); + insert(std::make_pair("KEY_TAPE", 0x180)); + insert(std::make_pair("KEY_RADIO", 0x181)); + insert(std::make_pair("KEY_TUNER", 0x182)); + insert(std::make_pair("KEY_PLAYER", 0x183)); + insert(std::make_pair("KEY_TEXT", 0x184)); + insert(std::make_pair("KEY_DVD", 0x185)); + insert(std::make_pair("KEY_AUX", 0x186)); + insert(std::make_pair("KEY_MP3", 0x187)); + insert(std::make_pair("KEY_AUDIO", 0x188)); + insert(std::make_pair("KEY_VIDEO", 0x189)); + insert(std::make_pair("KEY_DIRECTORY", 0x18a)); + insert(std::make_pair("KEY_LIST", 0x18b)); + insert(std::make_pair("KEY_MEMO", 0x18c)); + insert(std::make_pair("KEY_CALENDAR", 0x18d)); + insert(std::make_pair("KEY_RED", 0x18e)); + insert(std::make_pair("KEY_GREEN", 0x18f)); + insert(std::make_pair("KEY_YELLOW", 0x190)); + insert(std::make_pair("KEY_BLUE", 0x191)); + insert(std::make_pair("KEY_CHANNELUP", 0x192)); + insert(std::make_pair("KEY_CHANNELDOWN", 0x193)); + insert(std::make_pair("KEY_FIRST", 0x194)); + insert(std::make_pair("KEY_LAST", 0x195)); + insert(std::make_pair("KEY_AB", 0x196)); + insert(std::make_pair("KEY_NEXT", 0x197)); + insert(std::make_pair("KEY_RESTART", 0x198)); + insert(std::make_pair("KEY_SLOW", 0x199)); + insert(std::make_pair("KEY_SHUFFLE", 0x19a)); + insert(std::make_pair("KEY_BREAK", 0x19b)); + insert(std::make_pair("KEY_PREVIOUS", 0x19c)); + insert(std::make_pair("KEY_DIGITS", 0x19d)); + insert(std::make_pair("KEY_TEEN", 0x19e)); + insert(std::make_pair("KEY_TWEN", 0x19f)); + insert(std::make_pair("KEY_DEL_EOL", 0x1c0)); + insert(std::make_pair("KEY_DEL_EOS", 0x1c1)); + insert(std::make_pair("KEY_INS_LINE", 0x1c2)); + insert(std::make_pair("KEY_DEL_LINE", 0x1c3)); + insert(std::make_pair("KEY_FN", 0x1d0)); + insert(std::make_pair("KEY_FN_ESC", 0x1d1)); + insert(std::make_pair("KEY_FN_F1", 0x1d2)); + insert(std::make_pair("KEY_FN_F2", 0x1d3)); + insert(std::make_pair("KEY_FN_F3", 0x1d4)); + insert(std::make_pair("KEY_FN_F4", 0x1d5)); + insert(std::make_pair("KEY_FN_F5", 0x1d6)); + insert(std::make_pair("KEY_FN_F6", 0x1d7)); + insert(std::make_pair("KEY_FN_F7", 0x1d8)); + insert(std::make_pair("KEY_FN_F8", 0x1d9)); + insert(std::make_pair("KEY_FN_F9", 0x1da)); + insert(std::make_pair("KEY_FN_F10", 0x1db)); + insert(std::make_pair("KEY_FN_F11", 0x1dc)); + insert(std::make_pair("KEY_FN_F12", 0x1dd)); + insert(std::make_pair("KEY_FN_1", 0x1de)); + insert(std::make_pair("KEY_FN_2", 0x1df)); + insert(std::make_pair("KEY_FN_D", 0x1e0)); + insert(std::make_pair("KEY_FN_E", 0x1e1)); + insert(std::make_pair("KEY_FN_F", 0x1e2)); + insert(std::make_pair("KEY_FN_S", 0x1e3)); + insert(std::make_pair("KEY_FN_B", 0x1e4)); + insert(std::make_pair("KEY_BRL_DOT1", 0x1f1)); + insert(std::make_pair("KEY_BRL_DOT2", 0x1f2)); + insert(std::make_pair("KEY_BRL_DOT3", 0x1f3)); + insert(std::make_pair("KEY_BRL_DOT4", 0x1f4)); + insert(std::make_pair("KEY_BRL_DOT5", 0x1f5)); + insert(std::make_pair("KEY_BRL_DOT6", 0x1f6)); + insert(std::make_pair("KEY_BRL_DOT7", 0x1f7)); + insert(std::make_pair("KEY_BRL_DOT8", 0x1f8)); + //insert(std::make_pair("KEY_MIN_INTERESTING", KEY_MUTE)); + insert(std::make_pair("KEY_MAX", 0x1ff)); + insert(std::make_pair("REL_X", 0x00)); + insert(std::make_pair("REL_Y", 0x01)); + insert(std::make_pair("REL_Z", 0x02)); + insert(std::make_pair("REL_RX", 0x03)); + insert(std::make_pair("REL_RY", 0x04)); + insert(std::make_pair("REL_RZ", 0x05)); + insert(std::make_pair("REL_HWHEEL", 0x06)); + insert(std::make_pair("REL_DIAL", 0x07)); + insert(std::make_pair("REL_WHEEL", 0x08)); + insert(std::make_pair("REL_MISC", 0x09)); + insert(std::make_pair("REL_MAX", 0x0f)); + insert(std::make_pair("ABS_X", 0x00)); + insert(std::make_pair("ABS_Y", 0x01)); + insert(std::make_pair("ABS_Z", 0x02)); + insert(std::make_pair("ABS_RX", 0x03)); + insert(std::make_pair("ABS_RY", 0x04)); + insert(std::make_pair("ABS_RZ", 0x05)); + insert(std::make_pair("ABS_THROTTLE", 0x06)); + insert(std::make_pair("ABS_RUDDER", 0x07)); + insert(std::make_pair("ABS_WHEEL", 0x08)); + insert(std::make_pair("ABS_GAS", 0x09)); + insert(std::make_pair("ABS_BRAKE", 0x0a)); + insert(std::make_pair("ABS_HAT0X", 0x10)); + insert(std::make_pair("ABS_HAT0Y", 0x11)); + insert(std::make_pair("ABS_HAT1X", 0x12)); + insert(std::make_pair("ABS_HAT1Y", 0x13)); + insert(std::make_pair("ABS_HAT2X", 0x14)); + insert(std::make_pair("ABS_HAT2Y", 0x15)); + insert(std::make_pair("ABS_HAT3X", 0x16)); + insert(std::make_pair("ABS_HAT3Y", 0x17)); + insert(std::make_pair("ABS_PRESSURE", 0x18)); + insert(std::make_pair("ABS_DISTANCE", 0x19)); + insert(std::make_pair("ABS_TILT_X", 0x1a)); + insert(std::make_pair("ABS_TILT_Y", 0x1b)); + insert(std::make_pair("ABS_TOOL_WIDTH", 0x1c)); + insert(std::make_pair("ABS_VOLUME", 0x20)); + insert(std::make_pair("ABS_MISC", 0x28)); + insert(std::make_pair("ABS_MAX", 0x3f)); + insert(std::make_pair("SW_LID", 0x00)); + insert(std::make_pair("SW_TABLET_MODE", 0x01)); + insert(std::make_pair("SW_HEADPHONE_INSERT", 0x02)); + insert(std::make_pair("SW_MAX", 0x0f)); + insert(std::make_pair("MSC_SERIAL", 0x00)); + insert(std::make_pair("MSC_PULSELED", 0x01)); + insert(std::make_pair("MSC_GESTURE", 0x02)); + insert(std::make_pair("MSC_RAW", 0x03)); + insert(std::make_pair("MSC_SCAN", 0x04)); + insert(std::make_pair("MSC_MAX", 0x07)); + insert(std::make_pair("LED_NUML", 0x00)); + insert(std::make_pair("LED_CAPSL", 0x01)); + insert(std::make_pair("LED_SCROLLL", 0x02)); + insert(std::make_pair("LED_COMPOSE", 0x03)); + insert(std::make_pair("LED_KANA", 0x04)); + insert(std::make_pair("LED_SLEEP", 0x05)); + insert(std::make_pair("LED_SUSPEND", 0x06)); + insert(std::make_pair("LED_MUTE", 0x07)); + insert(std::make_pair("LED_MISC", 0x08)); + insert(std::make_pair("LED_MAIL", 0x09)); + insert(std::make_pair("LED_CHARGING", 0x0a)); + insert(std::make_pair("LED_MAX", 0x0f)); +} + +unsigned long +av::daemon::LinuxEvent::getEventCode(const std::string& eventType) +{ + const_iterator return_value = sEventMap.find(eventType); + return (return_value != sEventMap.end()) ? return_value->second : 0; +} diff --git a/avango-daemon/src/avango/daemon/SharedMemorySegment.cpp b/avango-daemon/src/avango/daemon/SharedMemorySegment.cpp new file mode 100644 index 00000000..1a0655d3 --- /dev/null +++ b/avango-daemon/src/avango/daemon/SharedMemorySegment.cpp @@ -0,0 +1,274 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include // errno +#include // EXIT_FAILURE, ::exit +#include // ::strerror +#include // std::cerr, std::cout, std::endl +#include // ::ftok +#include // ::shmat, ::shmctl, ::shmdt, ::shmget + +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::SharedMemorySegment")); + + const bool segment_info_printing_enabled = (0 != ::getenv("AVANGO_STATIONSEGMENT_INFO_ENABLED")); + + void + print_shm_segment_info (ssize_t key, ssize_t id, const char* extra_text = 0) + { + if (!segment_info_printing_enabled) + return; + + struct ::shmid_ds info; + + if (-1 == ::shmctl(id, IPC_STAT, &info)) { + std::cerr << "::print_shm_segment_info: " + << "shmctl(" << id << ", IPC_STAT, &info) for key " + << std::hex << key << std::dec + << " failed with reason '" + << ::strerror(errno) << "'" << std::endl; + + return; + } + + std::cout << "::print_shm_segment_info: "; + + if (extra_text) + std::cout << extra_text; + + std::cout << std::endl; + + std::cout << " shm_perm.key : " + << std::hex +#if defined(__GLIBC__) + << info.shm_perm.__key +#else + << info.shm_perm.key +#endif + << std::dec + << std::endl; + + std::cout << " shm_perm.owner : " + << info.shm_perm.uid << ':' << info.shm_perm.gid + << std::endl; + + std::cout << " shm_perm.creator : " + << info.shm_perm.cuid << ':' << info.shm_perm.cgid + << std::endl; + + std::cout << " shm_perm.mode : " + << info.shm_perm.mode + << std::endl; + + std::cout << " shm_perm.seq : " +#if defined(__GLIBC__) + << info.shm_perm.__seq +#else + << info.shm_perm.seq +#endif + << std::endl; + + std::cout << " size : " + << info.shm_segsz + << " byte" << ((1 < info.shm_segsz) ? "s" : "") + << std::endl; + + std::cout << " creator pid : " + << info.shm_cpid + << std::endl; + + std::cout << " last operator pid : " + << info.shm_lpid + << std::endl; + + std::cout << " # of attaches : " + << info.shm_nattch + << std::endl; + + std::cout << " last shmat : " + << ((0 == info.shm_atime) ? "never" : ::asctime(::localtime(&info.shm_atime))) + << std::endl; + + std::cout << " last shmdt : " + << ((0 == info.shm_dtime) ? "never" : ::asctime(::localtime(&info.shm_dtime))) + << std::endl; + + std::cout << " last change by shmctl : " + << ((0 == info.shm_ctime) ? "never" : ::asctime(::localtime(&info.shm_ctime))) + << std::endl; + } + +} + +av::daemon::SharedMemorySegment::SharedMemorySegment(int a, int b) + : mCreated(false), + mSegmentKey(::ftok("/dev/zero", a)), + mSegmentId(-1), + mSegment(0), + mSegmentSize(b) +{ + if (-1 == mSegmentKey) { + logger.error() << "SharedMemorySegment(): invalid segment key " << mSegmentKey << ", reason " << ::strerror(errno); + } + + if (-1 == (mSegmentId = ::shmget (mSegmentKey, mSegmentSize, IPC_CREAT|0777))) { + logger.warn() << "SharedMemorySegment(): shmget( %x, %d, IPC_CREAT|0777) failed with reason: %s", + mSegmentKey, mSegmentSize, ::strerror(errno); + + mSegmentSize = 0; + + throw std::runtime_error("Could not create shared memory segment!"); + } + + print_shm_segment_info (mSegmentKey, mSegmentId, "before shmat"); + + // find out if we created or joined the shm segment before attaching to it + struct ::shmid_ds segment_info; + + if (-1 == ::shmctl(mSegmentId, IPC_STAT, &segment_info)) { + logger.warn() << "SharedMemorySegment(): shmctl(" << mSegmentKey << ", IPC_STAT, &segment_info) failed with reason: " + << ::strerror(errno); + + mSegmentSize = 0; + + throw std::runtime_error("Could not determine shared memory segment info!"); + } + + const bool we_are_first = (0 == segment_info.shm_nattch) ? true : false; + + if (!we_are_first && (mSegmentSize > segment_info.shm_segsz)) { + logger.warn() << "SharedMemorySegment(): expected segment size (" << mSegmentSize << " byte" + << ((1 < mSegmentSize) ? "s" : "") << ") less than actual segment size (" + << segment_info.shm_segsz << " byte" << ((1 < segment_info.shm_segsz) ? "s" : "") << ")"; + + const uid_t euid = ::geteuid(); + + if (segment_info.shm_perm.uid == euid || segment_info.shm_perm.cuid == euid || 0 == euid) + { + logger.info() << "SharedMemorySegment(): attempting to resize segment size to " + << mSegmentSize << " byte" << ((1 < mSegmentSize) ? "s" : ""); + + segment_info.shm_segsz = mSegmentSize; + + if (-1 == ::shmctl(mSegmentId, IPC_SET, &segment_info)) + logger.warn() << "SharedMemorySegment(): resize operation shmctl(" << mSegmentKey + << ", IPC_SET, &segment_info) failed with reason " << ::strerror(errno) + << " good look though"; + else + { + if (-1 == ::shmctl(mSegmentId, IPC_STAT, &segment_info)) { + logger.warn() << "SharedMemorySegment(): shmctl(" << mSegmentKey << ", IPC_STAT, &segment_info) failed with reason: " + << ::strerror(errno); + + mSegmentSize = 0; + + throw std::runtime_error("Could not determine shared memory segment info!"); + } + + print_shm_segment_info (mSegmentKey, mSegmentId, "after resize, before shmat"); + + if (mSegmentSize == segment_info.shm_segsz) + logger.warn() << "SharedMemorySegment(): succesfully resized segment size to " << segment_info.shm_segsz + << " byte" << ((1 < segment_info.shm_segsz) ? "s" : "") << " for shm key <0x" + << mSegmentKey << "> (fd: " << mSegmentId << ")"; + else + { + logger.warn() << "SharedMemorySegment(): resizing segment size for shm key <0x" << mSegmentKey + << "> (fd: " << mSegmentId << ") failed; " << "again good look"; + } + } + } + else + logger.warn() << "SharedMemorySegment(): insufficient rights to resize segment size for shm key <0x" + << mSegmentKey << "> (fd: " << mSegmentId << "); " << "good look though"; + } + + // actually reference the shm segment + mSegment = ::shmat(mSegmentId, 0, 0); + + if (!mSegment) + { + logger.warn() << "SharedMemorySegment(): attaching to shm key <0x" + << mSegmentKey << "> failed; reason: " << ::strerror(errno); + + mSegmentSize = 0; + throw std::runtime_error("Could not attach to shared memory segment!"); + } + + print_shm_segment_info(mSegmentKey, mSegmentId, "after shmat"); + + logger.info() << "SharedMemorySegment(): %s shm key <0x%x> @0x%x (fd: %d)", + (we_are_first ? "created" : "joined"), mSegmentKey, mSegment, mSegmentId; + + mCreated = we_are_first && mSegment; +} + +av::daemon::SharedMemorySegment::~SharedMemorySegment() +{ + if (mSegment) + { + if (-1 == ::shmdt(mSegment)) + return; + + struct ::shmid_ds segment_info; + + if (-1 == ::shmctl(mSegmentId, IPC_STAT, &segment_info)) + return; + + // if there are no more processes attached then remove the segment + // note: user must be the (effectively) owner, creator, or the super-user + // to do this + + const uid_t euid = ::geteuid(); + + if (0 == segment_info.shm_nattch && + (segment_info.shm_perm.uid == euid || segment_info.shm_perm.cuid == euid || 0 == euid)) + if (-1 == ::shmctl(mSegmentId, IPC_RMID, 0)) + return; + } +} + +void* +av::daemon::SharedMemorySegment::segment() const +{ + return mSegment; +} + +size_t +av::daemon::SharedMemorySegment::size() const +{ + return mSegmentSize; +} + +bool +av::daemon::SharedMemorySegment::created() const +{ + return mCreated; +} diff --git a/avango-daemon/src/avango/daemon/Station.cpp b/avango-daemon/src/avango/daemon/Station.cpp new file mode 100644 index 00000000..8384bdcf --- /dev/null +++ b/avango-daemon/src/avango/daemon/Station.cpp @@ -0,0 +1,200 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include + +AV_BASE_DEFINE(av::daemon::Station); + +av::daemon::Station::Station() + : mName(), + mMatrix(), + mButton(), + mValue(), + mLed(), + mMatrixUsed(false), + mButtonsUsed(0), + mValuesUsed(0), + mLedsUsed(0) +{ + mName[sMaxNameLength - 1] = '\0'; + + for (int i=0; i +av::daemon::Station::getButtons() const +{ + return std::vector (mButton, mButton + sMaxButtons); +} + +float +av::daemon::Station::getValue(int which) const +{ + if (sMaxValues <= which) + return 0.0f; + + return mValue[which]; +} + +const std::vector +av::daemon::Station::getValues() const +{ + return std::vector (mValue, mValue + sMaxValues); +} + +bool +av::daemon::Station::getLED(int which) const +{ + if (sMaxLeds <= which) + return false; + + return mLed[which]; +} + +const std::vector +av::daemon::Station::getLEDs() const +{ + return std::vector (mLed, mLed + sMaxLeds); +} + +void +av::daemon::Station::setName(const char* name) +{ + ::strncpy(mName, name, sMaxNameLength - 2); + + mName[sMaxNameLength - 1] = '\0'; +} + +void +av::daemon::Station::setMatrix(const osg::Matrixf& matrix) +{ + mMatrix = matrix; +} + +void +av::daemon::Station::setButton(int which, int on) +{ + if (sMaxButtons <= which) + return; + + mButton[which] = on; +} + +void +av::daemon::Station::setValue(int which, float val) +{ + if (sMaxValues <= which) + return; + + mValue[which] = val; +} + +void +av::daemon::Station::setLED(int which, bool on) +{ + if (sMaxLeds <= which) + return; + + mLed[which] = on; +} + +bool +av::daemon::Station::getMatrixUsed() const +{ + return mMatrixUsed; +} + +int +av::daemon::Station::getButtonsUsed() const +{ + return mButtonsUsed; +} + +int +av::daemon::Station::getValuesUsed() const +{ + return mValuesUsed; +} + +int +av::daemon::Station::getLEDsUsed() const +{ + return mLedsUsed; +} + +void +av::daemon::Station::setUsage(bool matrix, int buttons, int values, int leds) +{ + mMatrixUsed = matrix; + mButtonsUsed = buttons; + mValuesUsed = values; + mLedsUsed = leds; +} diff --git a/avango-daemon/src/avango/daemon/StationBlock.cpp b/avango-daemon/src/avango/daemon/StationBlock.cpp new file mode 100644 index 00000000..ece3ba03 --- /dev/null +++ b/avango-daemon/src/avango/daemon/StationBlock.cpp @@ -0,0 +1,74 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::StationBlock")); +} + +av::daemon::StationBlock::StationBlock() + : mNumStations(0), + mMutex() +{} + +av::daemon::StationBlock::~StationBlock() +{} + +av::daemon::Station* +av::daemon::StationBlock::getStation(const char* name) +{ + // very simple and inefficient for now + Station* station = 0; + + boost::mutex::scoped_lock lock(mMutex); + + int i; + + for (i=0; isetName(name); + logger.debug() << "getStation(): created station '" << name << "', " << station; + + mNumStations++; + } + + return station; +} diff --git a/avango-daemon/src/avango/daemon/StationSegment.cpp b/avango-daemon/src/avango/daemon/StationSegment.cpp new file mode 100644 index 00000000..8c21a302 --- /dev/null +++ b/avango-daemon/src/avango/daemon/StationSegment.cpp @@ -0,0 +1,61 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include +#include + + +av::daemon::StationSegment::StationSegment() + : mSharedMem(new SharedMemorySegment (0xc3, sizeof(StationBlock))) +{ + AV_ASSERT(mSharedMem); + AV_ASSERT(mSharedMem->segment()); + + if (mSharedMem->created()) { + mStationBlock = new (mSharedMem->segment()) StationBlock; + } else { + mStationBlock = static_cast(mSharedMem->segment()); + } +} + +av::daemon::StationSegment::~StationSegment() +{ + delete mSharedMem; +} + +av::daemon::Station* +av::daemon::StationSegment::getStation(const char* name) +{ + return (mStationBlock) ? mStationBlock->getStation(name) : 0; +} + +av::daemon::Station* +av::daemon::StationSegment::getStation(const std::string& name) +{ + return getStation(name.c_str()); +} diff --git a/avango-daemon/src/avango/daemon/VRPNClient.cpp b/avango-daemon/src/avango/daemon/VRPNClient.cpp new file mode 100644 index 00000000..61efbb15 --- /dev/null +++ b/avango-daemon/src/avango/daemon/VRPNClient.cpp @@ -0,0 +1,184 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2009 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::VRPNClient")); + + void handle_analog(void *userdata, const vrpn_ANALOGCB a) + { + logger.trace() << "handle_analog: processing a VRPN analog event..."; + av::daemon::VRPNClient *device = reinterpret_cast(userdata); + device->handleAnalog(a); + } + + void handle_button(void *userdata, const vrpn_BUTTONCB b) + { + logger.trace() << "handle_button: processing a VRPN button event..."; + av::daemon::VRPNClient *device = reinterpret_cast(userdata); + device->handleButton(b); + } + + void handle_tracker(void *userdata, const vrpn_TRACKERCB t) + { + logger.trace() << "handle_tracker: processing a VRPN tracker event..."; + av::daemon::VRPNClient *device = reinterpret_cast(userdata); + device->handleTracker(t); + } +} + +AV_BASE_DEFINE(av::daemon::VRPNClient); + +av::daemon::VRPNClient::VRPNClient() +: mStopped(true), + mVRPNAnalog(0), + mVRPNButton(0), + mVRPNTracker(0) + +{ + mRequiredFeatures.push_back("server"); +} + +av::daemon::VRPNClient::~VRPNClient() +{ + delete mVRPNAnalog; + delete mVRPNButton; + delete mVRPNTracker; +} + +void +av::daemon::VRPNClient::initClass() +{ + if (!isTypeInitialized()) + { + av::daemon::Device::initClass(); + AV_BASE_INIT(av::daemon::Device, av::daemon::VRPNClient, true); + } +} + +const std::vector& +av::daemon::VRPNClient::queryFeatures() +{ + return mRequiredFeatures; +} + +bool +av::daemon::VRPNClient::parseFeatures() +{ + mVRPNServer = queryFeature("server"); + + if (mVRPNServer == "") + { + logger.error() << "parseFeatures: required feature 'server' not specified"; + return false; + } + return true; +} + +/* virtual */ void +av::daemon::VRPNClient::startDevice() +{ + if (!parseFeatures()) + { + logger.warn() << "startDevice: device not started!"; + return; + } + + mVRPNAnalog = new vrpn_Analog_Remote(mVRPNServer.c_str()); + mVRPNButton = new vrpn_Button_Remote(mVRPNServer.c_str()); + mVRPNTracker = new vrpn_Tracker_Remote(mVRPNServer.c_str()); + + mVRPNAnalog->register_change_handler(this, ::handle_analog); + mVRPNButton->register_change_handler(this, ::handle_button); + mVRPNTracker->register_change_handler(this, ::handle_tracker); + + mStopped = false; +} + +/* virtual */ void +av::daemon::VRPNClient::readLoop() +{ + while(mKeepRunning) + { + if (!mStopped) + { + if (mVRPNAnalog) mVRPNAnalog->mainloop(); + if (mVRPNButton) mVRPNButton->mainloop(); + if (mVRPNTracker) mVRPNTracker->mainloop(); + + vrpn_SleepMsecs(1); + } + } +} + +/* virtual */ void +av::daemon::VRPNClient::stopDevice() +{ + mVRPNAnalog->unregister_change_handler(this, ::handle_analog); + mVRPNButton->unregister_change_handler(this, ::handle_button); + mVRPNTracker->unregister_change_handler(this, ::handle_tracker); +} + +void +av::daemon::VRPNClient::handleAnalog(const vrpn_ANALOGCB a) +{ + NumStationMap::iterator ns; + + for (ns=mStations.begin(); ns!=mStations.end(); ns++) + for (int i=0; isetValue(i, a.channel[i]); +} + +void +av::daemon::VRPNClient::handleButton(const vrpn_BUTTONCB b) +{ + NumStationMap::iterator ns; + + for (ns=mStations.begin(); ns!=mStations.end(); ns++) + (*ns).second->setButton(b.button, b.state); +} + +void +av::daemon::VRPNClient::handleTracker(const vrpn_TRACKERCB t) +{ + NumStationMap::iterator ns; + + for (ns=mStations.begin(); ns!=mStations.end(); ns++) + { + ::osg::Matrixf pos_mat; + pos_mat.makeTranslate(t.pos[0], t.pos[1], t.pos[2]); + + ::osg::Matrixf rot_mat(::osg::Quat(t.quat[0],t.quat[1],t.quat[2],t.quat[3])); + pos_mat.preMult(rot_mat); + + (*ns).second->setMatrix(pos_mat); + } +} diff --git a/avango-daemon/src/avango/daemon/WacomTablet.cpp b/avango-daemon/src/avango/daemon/WacomTablet.cpp new file mode 100644 index 00000000..2e265165 --- /dev/null +++ b/avango-daemon/src/avango/daemon/WacomTablet.cpp @@ -0,0 +1,263 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::WacomTablet")); +} + +AV_BASE_DEFINE(av::daemon::WacomTablet); + +av::daemon::WacomTablet::WacomTablet() +{} + +av::daemon::WacomTablet::~WacomTablet() +{} + +void +av::daemon::WacomTablet::initClass() +{ + if (!isTypeInitialized()) + { + av::daemon::HIDInput::initClass(); + AV_BASE_INIT(av::daemon::HIDInput, av::daemon::WacomTablet, true); + } +} + +void +av::daemon::WacomTablet::startDevice() +{ + //auto-configure axes + std::string station = getFirstStation() + "::STATION_VALUE::"; + configureFeature(station + "0", "EV_ABS::ABS_X"); // Pen positon X axis + configureFeature(station + "1", "EV_ABS::ABS_Y"); // Pen position Y axis + configureFeature(station + "2", "EV_ABS::ABS_RX"); // Left touch strip + configureFeature(station + "3", "EV_ABS::ABS_RY"); // Right touch strip + configureFeature(station + "4", "EV_ABS::ABS_RZ"); // Rotation on 4d mouse + configureFeature(station + "5", "EV_ABS::ABS_THROTTLE"); // unused + configureFeature(station + "6", "EV_ABS::ABS_WHEEL"); // Wheel on airbrush pen + configureFeature(station + "7", "EV_ABS::ABS_PRESSURE"); // Pen pressure + configureFeature(station + "8", "EV_ABS::ABS_DISTANCE"); // Pen distance + configureFeature(station + "9", "EV_ABS::ABS_TILT_X"); // Pen tilt x axis + configureFeature(station + "10", "EV_ABS::ABS_TILT_Y"); // Pen tilt y axis + configureFeature(station + "11", "EV_REL::REL_WHEEL"); // Relative Wheel on mouse + configureFeature(station + "12", "AspectRatio"); // Ratio of Width/Height of Tablet + + //auto-configure buttons + station = getFirstStation() + "::STATION_BUTTON::"; + configureFeature(station + "0", "EV_KEY::BTN_0"); // Left Panel Button 1 + configureFeature(station + "1", "EV_KEY::BTN_1"); // Left Panel Button 2 + configureFeature(station + "2", "EV_KEY::BTN_2"); // Left Panel Button 3 + configureFeature(station + "3", "EV_KEY::BTN_3"); // Left Panel Button 4 + configureFeature(station + "4", "EV_KEY::BTN_4"); // Right Panel Button 1 + configureFeature(station + "5", "EV_KEY::BTN_5"); // Right Panel Button 2 + configureFeature(station + "6", "EV_KEY::BTN_6"); // Right Panel Button 3 + configureFeature(station + "7", "EV_KEY::BTN_7"); // Right Panel Button 4 + configureFeature(station + "8", "EV_KEY::BTN_LEFT"); // Left Mouse Button + configureFeature(station + "9", "EV_KEY::BTN_RIGHT"); // Right Mouse Button + configureFeature(station + "10", "EV_KEY::BTN_MIDDLE"); // Middle Mouse Button + configureFeature(station + "11", "EV_KEY::BTN_SIDE"); // unused + configureFeature(station + "12", "EV_KEY::BTN_EXTRA"); // unused + configureFeature(station + "13", "EV_KEY::BTN_TOOL_PEN"); // Regular pen in proximity + configureFeature(station + "14", "EV_KEY::BTN_TOOL_RUBBER"); // Rubber of pen/airbrush in prox + configureFeature(station + "15", "EV_KEY::BTN_TOOL_BRUSH"); // unused + configureFeature(station + "16", "EV_KEY::BTN_TOOL_PENCIL"); // unused + configureFeature(station + "17", "EV_KEY::BTN_TOOL_AIRBRUSH"); // Airbrush in proximity + configureFeature(station + "18", "EV_KEY::BTN_TOOL_FINGER"); // Panel-button or strip touched + configureFeature(station + "19", "EV_KEY::BTN_TOOL_MOUSE"); // Mouse in proximity + configureFeature(station + "20", "EV_KEY::BTN_TOOL_LENS"); // unused + configureFeature(station + "21", "EV_KEY::BTN_TOUCH"); // any tool touches tablet + configureFeature(station + "22", "EV_KEY::BTN_STYLUS"); // 1st side button on pen/airbrush + configureFeature(station + "23", "EV_KEY::BTN_STYLUS2"); // 2nd side button on pen + configureFeature(station + "24", "Proximity"); // true if anything in proximity + configureFeature(station + "25", "ToggleReset"); // should be true for Intuos3 +} + +void +av::daemon::WacomTablet::retrieveAspectRatio() +{ + HIDInput::AbsInfoMap::iterator it (mAbsInfoMap.find(0)); + const float x_max = (*it).second.maximum; + + it = (mAbsInfoMap.find(1)); + const float y_max = (*it).second.maximum; + + NumStationMap::iterator ns = mStations.begin(); + + if ((0 < x_max)&&(0 < y_max)) + (*ns).second->setValue(12,x_max/y_max); + else + (*ns).second->setValue(12,1); +} + +/* virtual */ void +av::daemon::WacomTablet::readLoop() +{ + float x,y; + ::osg::Matrixf matrix; + + if (!parse_features()) + { + logger.warn() << "startDevice: required features missing, not started."; + return; + } + + NumStationMap::iterator ns; + struct input_event event; + int reset_wait_counter(0); + + for (;;) + { + + while (!isOpen()) + { + if (open()) + { + retrieve_abs_info(); + retrieveAspectRatio(); + stopLEDs(); + startLEDs(); + } + else + { + logger.warn() << "readLoop: HID device is not open."; + // sleep 5 seconds + struct timeval timeout = { 5, 0 }; + while (0 != ::select(0, 0, 0, 0, &timeout)) {} + } + } + + updateLEDs(); + if (readEvent(&event)) { + reset_wait_counter = 0; + logger.trace() << "readLoop: time " << event.time.tv_sec << "." << event.time.tv_usec + << ", type " << event.type << ", code " << event.code << ", value " << event.value; + + for (ns = mStations.begin(); ns != mStations.end(); ++ns) + { + int station_index = ns->first; + if (!stationLooksForEvent(station_index, event)) { + continue; + } + applyEventToStation(station_index, event); + } + + //set Transform Matrix + ns = mStations.begin(); + x = (*ns).second->getValue(0); + y = (*ns).second->getValue(1); + matrix.makeTranslate(::osg::Vec3f(x,y,0.0f)); + (*ns).second->setMatrix(matrix); + + //set Proximity Value and reset some buttons which else get wrong values with normalization + for (int code=13; code<21; ++code) + { + if (0 == (*ns).second->getButton(code)) + { + if (code == 20) + { + (*ns).second->setButton(24,0); + if (mToggleReset) + { + (*ns).second->setValue(0,0); + (*ns).second->setValue(1,0); + (*ns).second->setValue(6,0); + (*ns).second->setValue(8,0); + (*ns).second->setValue(9,0); + (*ns).second->setValue(10,0); + } + } + } + else + { + (*ns).second->setButton(24,1); + code = 21; + } + } + } + else + { // timeout + ++reset_wait_counter; + // reset all EV_REL mappings to 0.0 if not accumulating relative values + if (!mAccumRel && (mResetRelCycle >= 0) && (reset_wait_counter >= mResetRelCycle)) + { + reset_wait_counter = 0; + clearRelativeStationValues(); + logger.trace() << "readLoop: resetting all EV_REL mappings."; + } + } + } + +} + +float +av::daemon::WacomTablet::normalizeAbsValue(const input_event& event) const +{ + float normalized_value = 0.0f; + HIDInput::AbsInfoMap::const_iterator iter (mAbsInfoMap.find(event.code)); + const input_absinfo& info = (*iter).second; + NumStationMap::const_iterator ns = mStations.begin(); + + switch (event.code) { + case ABS_RX: + case ABS_RY: + if (event.value>0.0) normalized_value = log(event.value)/log(2)+1; + else normalized_value = 0.0f; + break; + case ABS_PRESSURE: + if (event.value>0.0) + normalized_value = ((float)event.value -(float)info.minimum)/ (float)(info.maximum - info.minimum); + break; + case ABS_DISTANCE: + if (event.value < 50) normalized_value = 1.0f; + else normalized_value = 0.0f; + break; + case ABS_X: + case ABS_WHEEL: + case ABS_TILT_X: + normalized_value = 2.0f* ((float)event.value -(float)info.minimum) / (float)(info.maximum + info.minimum ) - 1.0f; + break; + case ABS_Y: + case ABS_TILT_Y: + normalized_value = -2.0f* ((float)event.value -(float)info.minimum) / (float)(info.maximum + info.minimum ) + 1.0f; + break; + default: + normalized_value = HIDInput::normalizeAbsValue(event); + } + + return normalized_value; +} + +/*virtual*/ int +av::daemon::WacomTablet::parse_features() +{ + if (HIDInput::parse_features()) + mToggleReset = HIDInput::scanForOptionalFeature("toggle-reset", false); + return 1; +} diff --git a/avango-daemon/src/avango/daemon/Wiimote.cpp b/avango-daemon/src/avango/daemon/Wiimote.cpp new file mode 100644 index 00000000..10290400 --- /dev/null +++ b/avango-daemon/src/avango/daemon/Wiimote.cpp @@ -0,0 +1,114 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::Wiimote")); +} + +AV_BASE_DEFINE(av::daemon::Wiimote); + +av::daemon::Wiimote::Wiimote() +{} + +av::daemon::Wiimote::~Wiimote() +{} + +void +av::daemon::Wiimote::initClass() +{ + if (!isTypeInitialized()) + { + av::daemon::HIDInput::initClass(); + AV_BASE_INIT(av::daemon::HIDInput, av::daemon::Wiimote, true); + } +} + +void +av::daemon::Wiimote::startDevice() +{ + // auto-configure LED and Rumble features + std::string stationLED = getFirstStation() + "::STATION_LED::"; + configureFeature(stationLED + "0", "EV_LED::LED_NUML"); // LED 0 + configureFeature(stationLED + "1", "EV_LED::LED_CAPSL"); // LED 1 + configureFeature(stationLED + "2", "EV_LED::LED_SCROLLL"); // LED 2 + configureFeature(stationLED + "3", "EV_LED::LED_COMPOSE"); // LED 3 + + configureFeature(stationLED + "5", "EV_LED::LED_SLEEP"); // Rumble 0 + configureFeature(stationLED + "6", "EV_LED::LED_SUSPEND"); // Rumble 1 + configureFeature(stationLED + "7", "EV_LED::LED_MUTE"); // Rumble 2 + configureFeature(stationLED + "8", "EV_LED::LED_MISC"); // Rumble 3 + configureFeature(stationLED + "9", "EV_LED::LED_MAIL"); // Rumble 4 + configureFeature(stationLED + "10", "EV_LED::LED_CHARGING");// Rumble 5 + configureFeature(stationLED + "11", "EV_LED::LED_SLEEP"); // Rumble 6 +} + +/* virtual */ void +av::daemon::Wiimote::updateLED(unsigned short eventCode, bool on) +{ + // be sure to have correct virtual rumble LED states in linux input system + if (on) { + switch (eventCode) { + case LED_SLEEP: + case LED_SUSPEND: + case LED_MUTE: + case LED_MISC: +#if defined(LED_MAIL) + case LED_MAIL: +#endif +#if defined(LED_CHARGING) + case LED_CHARGING: +#endif + case LED_MAX: + HIDInput::updateLED(eventCode, false); + } + } + HIDInput::updateLED(eventCode, on); +} + +/* virtual */ void +av::daemon::Wiimote::stopLEDs() +{ + HIDInput::stopLEDs(); + + // enable flashing + updateLED(LED_KANA, true); + + // disable rumble + updateLED(LED_SLEEP, false); + updateLED(LED_SUSPEND, false); + updateLED(LED_MUTE, false); + updateLED(LED_MISC, false); +#if defined(LED_MAIL) + updateLED(LED_MAIL, false); +#endif +#if defined(LED_CHARGING) + updateLED(LED_CHARGING, false); +#endif + updateLED(LED_MAX, false); +} diff --git a/avango-daemon/src/avango/daemon/WiimoteActuator.cpp b/avango-daemon/src/avango/daemon/WiimoteActuator.cpp new file mode 100644 index 00000000..46514525 --- /dev/null +++ b/avango-daemon/src/avango/daemon/WiimoteActuator.cpp @@ -0,0 +1,115 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace +{ + av::Logger& logger(av::getLogger("av::daemon::WiimoteActuator")); +} + +AV_FC_DEFINE(av::daemon::WiimoteActuator); + +av::daemon::WiimoteActuator::WiimoteActuator() +{ + AV_FC_ADD_FIELD(LED0, false); + AV_FC_ADD_FIELD(LED1, false); + AV_FC_ADD_FIELD(LED2, false); + AV_FC_ADD_FIELD(LED3, false); + AV_FC_ADD_FIELD(Rumble0, false); + AV_FC_ADD_FIELD(Rumble1, false); + AV_FC_ADD_FIELD(Rumble2, false); + AV_FC_ADD_FIELD(Rumble3, false); + AV_FC_ADD_FIELD(Rumble4, false); + AV_FC_ADD_FIELD(Rumble5, false); + AV_FC_ADD_FIELD(Rumble6, false); +} + +av::daemon::WiimoteActuator::~WiimoteActuator() +{ + reset(); +} + +void +av::daemon::WiimoteActuator::initClass() +{ + if (!isTypeInitialized()) + { + av::FieldContainer::initClass(); + AV_FC_INIT(av::FieldContainer, av::daemon::WiimoteActuator, true); + } +} + +/* virtual */ void +av::daemon::WiimoteActuator::evaluate() +{ + if (mService.isValid() && !(mStation.empty()) ) + { + const char* stationstr = mStation.c_str(); + + // set LED states + mService->setLED(stationstr, LED_NUML, LED0.getValue()); + mService->setLED(stationstr, LED_CAPSL, LED1.getValue()); + mService->setLED(stationstr, LED_SCROLLL, LED2.getValue()); + mService->setLED(stationstr, LED_COMPOSE, LED3.getValue()); + + // set rumble modes + mService->setLED(stationstr, LED_SLEEP, Rumble0.getValue()); + mService->setLED(stationstr, LED_SUSPEND, Rumble1.getValue()); + mService->setLED(stationstr, LED_MUTE, Rumble2.getValue()); + mService->setLED(stationstr, LED_MISC, Rumble3.getValue()); + mService->setLED(stationstr, LED_MAIL, Rumble4.getValue()); + mService->setLED(stationstr, LED_CHARGING, Rumble5.getValue()); + mService->setLED(stationstr, LED_MAX, Rumble6.getValue()); + } +} + +void +av::daemon::WiimoteActuator::reset() +{ + if (mService.isValid() && !(mStation.empty()) ) + { + logger.info() << "reset: reset LED and Rumble states"; + const char* stationstr = mStation.c_str(); + + mService->setLED(stationstr, LED_NUML, false); + mService->setLED(stationstr, LED_CAPSL, false); + mService->setLED(stationstr, LED_SCROLLL, false); + mService->setLED(stationstr, LED_COMPOSE, false); + + mService->setLED(stationstr, LED_SLEEP, false); + mService->setLED(stationstr, LED_SUSPEND, false); + mService->setLED(stationstr, LED_MUTE, false); + mService->setLED(stationstr, LED_MISC, false); + mService->setLED(stationstr, LED_MAIL, false); + mService->setLED(stationstr, LED_CHARGING, false); + mService->setLED(stationstr, LED_MAX, false); + } +} diff --git a/avango-daemon/src/avango/daemon/dtrack/dtrack.cpp b/avango-daemon/src/avango/daemon/dtrack/dtrack.cpp new file mode 100644 index 00000000..f23cb7a6 --- /dev/null +++ b/avango-daemon/src/avango/daemon/dtrack/dtrack.cpp @@ -0,0 +1,803 @@ +/* dtrack: receives and processes DTrack udp packets (ASCII protocol), A.R.T. GmbH 25.8.00-s.u. + * Common code tested under Linux, Irix, Windows NT 4.0, Windows 2000, Windows XP + * + * Version v0.3.4 + * + * Purpose: + * - receives DTrack udp packets (ASCII protocol) and converts them into easier to handle data + * - sends DTrack remote commands (udp) + * - DTrack network protocol due to: 'Technical Appendix DTrack v1.18 (July 7, 2003)' + * - for DTrack versions v1.16 - v1.20 (and compatible versions) + * + * Usage: + * - for Linux, Irix: just compile + * - for Windows NT 4.0, Windows 2000, Windows XP: + * - comment '#define OS_UNIX', uncomment '#define OS_WIN' + * - link with 'ws2_32.lib' + * + * Versions: + * v0.1 (25.8.00, KA): ASCII-Format + * v0.2 (10.3.01, KA): 'neues' Datenformat + * p1 (10.4.01, KA): Linux und NT + * p2 (26.9.01, KA): Protokoll-Erweiterung fuer DTrack v1.16.1: '6dcal' + * v0.3 (15.10.01, KA): Protokoll-Erweiterung fuer DTrack v1.16.2: '6df' + * p1 (11.1.02, KA): 'remote'-Schnittstelle + * p2 (29.1.03, KA): Timestamp-Erweiterung fuer DTrack v1.17.3 + * p3 (25.9.03, KA): Protokoll-Erweiterung fuer DTrack v1.18.0: '6dmt' + * p4 (26.5.04, KA): udp_receive erweitert (OS-Buffer komplett leeren) + * + */ + +#define OS_UNIX 1 // for Linux, Irix +//#define OS_WIN 1 // for Windows NT 4.0, Windows 2000, Windows XP + +// -------------------------------------------------------------------------- + +#include +#include +#include + +#ifdef OS_UNIX + #include + #include + #include + #include +#endif +#ifdef OS_WIN + #include + #include +#endif + +#include "dtrack.h" + +// Constants dependent from protocol: + +#define PROT_MAX_LINES 8 // maximum number of lines in a udp packet + + + +// -------------------------------------------------------------------------- +// Constructor & Destructor + +DTrack::DTrack() + : _udpsock(-1), + _udptimeout_us(1000000), + _udpbufsize(10000), + _udpbuf(NULL), + _remote_ip(0), + _remote_port(0) +{ +} + +DTrack::~DTrack() +{ +} + + +// -------------------------------------------------------------------------- +// Initialization: +// ini (i): parameters +// return value (o): error code + +int DTrack::init(dtrack_init_type* ini) +{ + + // init udp socket: + + _udpsock = udp_init(ini->udpport); + if(_udpsock < 0){ + return DTRACK_ERR_UDP; + } + + _udptimeout_us = ini->udptimeout_us; + + // init udp buffer: + + _udpbufsize = ini->udpbufsize; + + _udpbuf = (char *)malloc(_udpbufsize); + if(!_udpbuf){ + udp_exit(_udpsock); + return DTRACK_ERR_MEM; + } + + // DTrack remote control parameters: + + _remote_ip = udp_inet_atoh(ini->remote_ip); + _remote_port = ini->remote_port; + + return DTRACK_ERR_NONE; +} + + +// -------------------------------------------------------------------------- +// Exit: +// return value (o): error code + +int DTrack::exit(void) +{ + + // exit udp buffer: + + if(_udpbuf){ + free(_udpbuf); + } + + // exit udp socket: + + if(_udpsock > 0){ + if(udp_exit(_udpsock)){ + return DTRACK_ERR_UDP; + } + } + + return DTRACK_ERR_NONE; +} + + +// -------------------------------------------------------------------------- +// Receive and process DTrack udp packet (ASCII protocol): + +// framenr (o): frame counter +// timestamp (o): timestamp (-1, if information not available in packet) + +// nbodycal (o): number of calibrated bodies (-1, if information not available in packet) +// nbody (o): number of tracked bodies +// body (o): array containing 6d data +// max_nbody (i): maximum number of bodies in array body (no processing is done, if 0) + +// nflystick (o): number of calibrated flysticks +// flystick (o): array containing 6df data +// max_nflystick (i): maximum number of flysticks in array flystick (no processing is done, if 0) + +// nmeatool (o): number of calibrated measurement tools +// meatool (o): array containing 6dmt data +// max_nmeatool (i): maximum number of measurement tools in array (no processing is done, if 0) + +// nmarker (o): number of tracked single markers +// marker (o): array containing 3d data +// max_nmarker (i): maximum number of marker in array marker (no processing is done, if 0) + +// return value (o): error code + +int DTrack::receive_udp_ascii( + unsigned long* framenr, double* timestamp, + int* nbodycal, int* nbody, dtrack_body_type* body, int max_nbody, + int* nflystick, dtrack_flystick_type* flystick, int max_nflystick, + int* nmeatool, dtrack_meatool_type* meatool, int max_nmeatool, + int* nmarker, dtrack_marker_type* marker, int max_nmarker +){ + char* strs[PROT_MAX_LINES]; + char* s; + int iline, nlines; + int i, len, n; + unsigned long ul, ularr[2]; + + // Defaults: + + *framenr = 0; + *timestamp = -1; // i.e. not available + *nbodycal = -1; // i.e. not available + *nbody = 0; + *nflystick = 0; + *nmeatool = 0; + *nmarker = 0; + + // Receive udp packet: + + len = udp_receive(_udpsock, _udpbuf, _udpbufsize, _udptimeout_us); + + if(len == -1){ + return DTRACK_ERR_TIMEOUT; + } + if(len <= 0){ + return DTRACK_ERR_UDP; + } + + // Split packet in lines: + + if((nlines = split_lines(_udpbuf, len, strs, PROT_MAX_LINES)) == 0){ + return DTRACK_ERR_PCK; + } + + // Process lines: + + for(iline=0; iline max_nbody){ + n = max_nbody; + } + + for(i=0; i max_nflystick){ + n = max_nflystick; + } + + for(i=0; i max_nmeatool){ + n = max_nmeatool; + } + + for(i=0; i max_nmarker){ + n = max_nmarker; + } + + for(i=0; i= maxlen){ // buffer overflow + return -4; + } + + return nbytes; + } + } +} + + +// Sending udp data: +// sock (i): socket number +// buffer (i): buffer for udp data +// len (i): length of buffer +// ipaddr (i): ip address to send to +// port (i): port number to send to +// tout_us (i): timeout in us (micro sec) +// return value (o): 0 if ok, <0 if error/timeout occured + +int DTrack::udp_send(int sock, void* buffer, int len, unsigned long ipaddr, unsigned short port, unsigned long tout_us) +{ + fd_set set; + struct timeval tout; + int nbytes, err; + struct sockaddr_in addr; + + // building address: + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(ipaddr); + addr.sin_port = htons(port); + + // waiting to send data: + + FD_ZERO(&set); + FD_SET(sock, &set); + + tout.tv_sec = tout_us / 1000000; + tout.tv_usec = tout_us % 1000000; + + switch((err = select(FD_SETSIZE, NULL, &set, NULL, &tout))){ + case 1: + break; + case 0: + return -1; // timeout + default: + return -2; // error + } + + // sending data: + + nbytes = sendto(sock, (char* )buffer, len, 0, (struct sockaddr* )&addr, (size_t )sizeof(struct sockaddr_in)); + + if(nbytes < len){ // send error + return -3; + } + + return 0; +} + + +// Converting string to ip address: +// s (i): string +// return value (o): ip address, 0 if error occured + +unsigned long DTrack::udp_inet_atoh(char* s) +{ + int i, a[4]; + char* s1; + unsigned long ret; + + s1 = s; + while(*s1){ + if(*s1 == '.'){ + *s1 = ' '; + } + s1++; + } + + if(sscanf(s, "%d %d %d %d", &a[0], &a[1], &a[2], &a[3]) != 4){ + return 0; + } + + ret = 0; + for(i=0; i<4; i++){ + if(a[i] < 0 || a[i] > 255){ + return 0; + } + + ret = (ret << 8) | (unsigned char)a[i]; + } + + return ret; +} diff --git a/avango-daemon/src/avango/daemon/dtrack/dtrack.h b/avango-daemon/src/avango/daemon/dtrack/dtrack.h new file mode 100644 index 00000000..c3fc9b5c --- /dev/null +++ b/avango-daemon/src/avango/daemon/dtrack/dtrack.h @@ -0,0 +1,199 @@ +/* dtrack: receives and processes DTrack udp packets (ASCII protocol), A.R.T. GmbH 25.8.00-26.5.04 + * Common code for Unix/Linux/Windows NT/Windows 2000/Windows XP + * + * Version v0.3.4 + * + * DTrack network protocol due to: 'Technical Appendix DTrack v1.18 (July 7, 2003)' + * for DTrack versions v1.16 - v1.20 (and compatible versions) + * + */ + +#ifndef _ART_DTRACK_H +#define _ART_DTRACK_H + + +// -------------------------------------------------------------------------- +// Error codes: + +#define DTRACK_ERR_NONE 0 +#define DTRACK_ERR_UDP -1 // error handling the udp socket +#define DTRACK_ERR_MEM -2 // error handling the udp buffer +#define DTRACK_ERR_TIMEOUT -3 // timeout while receiving data +#define DTRACK_ERR_CMD -4 // error while sending remote command +#define DTRACK_ERR_PCK -10 // error in udp packet + + +// -------------------------------------------------------------------------- +// DTrack remote commands: + +#define DTRACK_CMD_CAMERAS_OFF 0x1000 +#define DTRACK_CMD_CAMERAS_ON 0x1001 +#define DTRACK_CMD_CAMERAS_AND_CALC_ON 0x1003 + +#define DTRACK_CMD_SEND_DATA 0x3100 +#define DTRACK_CMD_STOP_DATA 0x3200 +#define DTRACK_CMD_SEND_N_DATA 0x3300 + + +// -------------------------------------------------------------------------- +// Initialize Lib + +// Initialization parameters: + +typedef struct{ + unsigned short udpport; // udp port number + int udpbufsize; // size of buffer for udp packets (in bytes) + unsigned long udptimeout_us; // udp timeout (receiving and sending) in us (micro sec) + + char remote_ip[20]; // DTrack remote control: ip address of DTrack pc ("\0" if not used) + unsigned short remote_port; // port number of DTrack remote control (0 if not used) +} dtrack_init_type; + + +// -------------------------------------------------------------------------- +// Receiving DTrack data + +// Body data (6d): + +typedef struct{ + unsigned long id; // id number + float quality; // quality (0 <= qu <= 1) + float loc[3]; // location (in mm) + float ang[3]; // orientation angles (eta, theta, phi; in deg) + float rot[9]; // rotation matrix (column-wise) +} dtrack_body_type; + +// Flystick data (6d + buttons): + +typedef struct{ + unsigned long id; // id number + float quality; // quality (0 <= qu <= 1, no tracking if -1) + unsigned long bt; // pressed buttons (binary coded) + float loc[3]; // location (in mm) + float ang[3]; // orientation angles (eta, theta, phi; in deg) + float rot[9]; // rotation matrix (column-wise) +} dtrack_flystick_type; + +// Measurement tool data (6d + buttons): + +typedef struct{ + unsigned long id; // id number + float quality; // quality (0 <= qu <= 1, no tracking if -1) + unsigned long bt; // pressed buttons (binary coded) + float loc[3]; // location (in mm) + float rot[9]; // rotation matrix (column-wise) +} dtrack_meatool_type; + +// Single marker data (3d): + +typedef struct{ + unsigned long id; // id number + float quality; // quality (0 <= qu <= 1) + float loc[3]; // location (in mm) +} dtrack_marker_type; + + + +// -------------------------------------------------------------------------- +// DTrack class (quick&dirty-hack to enscapulate connection dependend data) + +class DTrack +{ + public: + + DTrack(); + ~DTrack(); + + // -------------------------------------------------------------------------- + // Initialize Lib + + // Initialization: + // ini (i): parameters + // return value (o): error code + + int init(dtrack_init_type* ini); + + // Exit: + // return value (o): error code + + int exit(void); + + + // -------------------------------------------------------------------------- + // Receiving DTrack data + + // Receive and process DTrack udp packet (ASCII protocol): + + // framenr (o): frame counter + // timestamp (o): timestamp (-1, if information not available in packet) + + // nbodycal (o): number of calibrated bodies (-1, if information not available in packet) + // nbody (o): number of tracked bodies + // body (o): array containing 6d data + // max_nbody (i): maximum number of bodies in array body (no processing is done, if 0) + + // nflystick (o): number of calibrated flysticks + // flystick (o): array containing 6df data + // max_nflystick (i): maximum number of flysticks in array flystick (no processing is done, if 0) + + // nmeatool (o): number of calibrated measurement tools + // meatool (o): array containing 6dmt data + // max_nmeatool (i): maximum number of measurement tools in array (no processing is done, if 0) + + // nmarker (o): number of tracked single markers + // marker (o): array containing 3d data + // max_nmarker (i): maximum number of marker in array marker (no processing is done, if 0) + + // return value (o): error code + + int receive_udp_ascii( + unsigned long* framenr, double* timestamp, + int* nbodycal, int* nbody, dtrack_body_type* body, int max_nbody, + int* nflystick, dtrack_flystick_type* flystick, int max_nflystick, + int* nmeatool, dtrack_meatool_type* meatool, int max_nmeatool, + int* nmarker, dtrack_marker_type* marker, int max_nmarker + ); + + + // --------------------------------------------------------------------------------------------------- + // DTrack remote control + + // Send remote control command (udp) to DTrack: + + // cmd (i): command code + // val (i): additional value (if needed) + // return value (o): error code + + int send_udp_command(unsigned short cmd, int val); + + protected: + + static int split_lines(char* str, unsigned long len, char** strarr, int maxlines); + + static char* get_ul(const char* str, unsigned long* ul); + static char* get_d(const char* str, double* d); + static char* get_f(const char* str, float* f); + static char* get_block(char* str, const char* fmt, unsigned long* uldat, float* fdat); + + static int udp_init(unsigned short port); + static int udp_exit(int sock); + static int udp_receive(int sock, void *buffer, int maxlen, unsigned long tout_us); + static int udp_send(int sock, void* buffer, int len, unsigned long ipaddr, unsigned short port, unsigned long tout_us); + + static unsigned long udp_inet_atoh(char* s); + + private: + + int _udpsock; // socket number for udp + unsigned long _udptimeout_us; // timeout for receiving and sending + + int _udpbufsize; // size of udp buffer + char* _udpbuf; // udp buffer + + unsigned long _remote_ip; // DTrack remote command access: ip address + unsigned short _remote_port; // DTrack remote command access: port number +}; + + + +#endif // _ART_DTRACK_H diff --git a/avango-daemon/src/avango/daemon/tests/TestApplicationSide.cpp b/avango-daemon/src/avango/daemon/tests/TestApplicationSide.cpp new file mode 100644 index 00000000..7d07e493 --- /dev/null +++ b/avango-daemon/src/avango/daemon/tests/TestApplicationSide.cpp @@ -0,0 +1,47 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include + +using namespace av::daemon; + +namespace { + + TEST(ServiceCanBeInitialized) + { + av::daemon::DeviceService::initClass(); + CHECK(av::Type::getByName("av::daemon::DeviceService") != av::Type::badType()); + } + TEST(SensorCanBeInitialized) + { + av::daemon::DeviceSensor::initClass(); + CHECK(av::Type::getByName("av::daemon::DeviceSensor") != av::Type::badType()); + } +} diff --git a/avango-daemon/src/avango/daemon/tests/TestAvangoDaemon.cpp b/avango-daemon/src/avango/daemon/tests/TestAvangoDaemon.cpp new file mode 100644 index 00000000..108d1f84 --- /dev/null +++ b/avango-daemon/src/avango/daemon/tests/TestAvangoDaemon.cpp @@ -0,0 +1,42 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +int main() +{ + av::getRootLogger().addConsoleAppender(); + av::ApplicationInstance::get(); + return UnitTest::RunAllTests(); +} diff --git a/avango-daemon/src/avango/daemon/tests/TestDaemonSide.cpp b/avango-daemon/src/avango/daemon/tests/TestDaemonSide.cpp new file mode 100644 index 00000000..7159a801 --- /dev/null +++ b/avango-daemon/src/avango/daemon/tests/TestDaemonSide.cpp @@ -0,0 +1,53 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include + +#include + +#include +#include +#include + +using namespace av::daemon; + +namespace { + + TEST(HIDInputCanBeInitialized) + { + av::daemon::HIDInput::initClass(); + CHECK(av::Type::getByName("av::daemon::HIDInput") != av::Type::badType()); + } + TEST(DTrackCanBeInitialized) + { + av::daemon::DTrack::initClass(); + CHECK(av::Type::getByName("av::daemon::DTrack") != av::Type::badType()); + } + TEST(WiimoteCanBeInitialized) + { + av::daemon::Wiimote::initClass(); + CHECK(av::Type::getByName("av::daemon::Wiimote") != av::Type::badType()); + } +} diff --git a/avango-daemon/src/examples/README b/avango-daemon/src/examples/README new file mode 100644 index 00000000..8728fd8b --- /dev/null +++ b/avango-daemon/src/examples/README @@ -0,0 +1,41 @@ +// -*- Mode:Outline -*- + +########################################################################## +# # +# This file is part of AVANGO. # +# # +# Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der # +# angewandten Forschung (FhG), Munich, Germany. # +# # +# AVANGO is free software: you can redistribute it and/or modify # +# it under the terms of the GNU Lesser General Public License as # +# published by the Free Software Foundation, version 3. # +# # +# AVANGO is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU Lesser General Public # +# License along with AVANGO. If not, see . # +# # +########################################################################## + + +This example shows the compatibility of an Avango Classic fpHIDInput running +in the device daemon (av-daemon) to an instances of DeviceService and +DeviceSensor of the Avango NG framework. + +Usage: + + 1. Start Avango Classic Tracker: + + ~/old-avango/bin/./av-daemon.sh -f devices.scm + + NOTE: For parametrization look into the file. + + + 2. Start TestDevice using Avango NG instances: + + ./TestDevice + diff --git a/avango-daemon/src/examples/TestDevice.cpp b/avango-daemon/src/examples/TestDevice.cpp new file mode 100644 index 00000000..5a879acd --- /dev/null +++ b/avango-daemon/src/examples/TestDevice.cpp @@ -0,0 +1,63 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#include +#include +#include +#include +#include +#include + +int main() +{ + std::cout << "Reading mouse values ..." << std::endl; + + av::Logger& logger = av::Logger::getLogger("av::daemon::SharedMemorySegment"); + + boost::shared_ptr console_app = av::logging::ConsoleAppender::getInstanceSharedPtr(); + logger.addAppender(console_app); + + osg::Matrixf* identity(new osg::Matrixf()); + av::daemon::DeviceService* serv = new av::daemon::DeviceService; + av::daemon::DeviceSensor* sens = new av::daemon::DeviceSensor(); + sens->DeviceService.setValue(serv); + sens->Station.setValue("mouse-station"); + + while(true) + { + sens->evaluate(); + + // output directly from DeviceService + //std::cout << "Service (Value X): "<< serv->getValue("mouse-station", 0) << std::endl; + //std::cout << "Service (Value Y): "<< serv->getValue("mouse-station", 1) << std::endl; + + // output coming from DeviceSensor + std::cout << "Sensor (Value X): "<< sens->Value0.getValue() << std::endl; + std::cout << "Sensor (Value Y): "<< sens->Value1.getValue() << std::endl; + } + + return 1; +} + diff --git a/avango-daemon/src/examples/devices.scm b/avango-daemon/src/examples/devices.scm new file mode 100644 index 00000000..7827991d --- /dev/null +++ b/avango-daemon/src/examples/devices.scm @@ -0,0 +1,20 @@ +(require 'av-linux-event) + +(add-device "mouse" "fpHIDInput") +(config-device "mouse" "tty" "/dev/input/event1") +(config-device "mouse" "vendor" "0x046D") +(config-device "mouse" "product" "0xC016") +(config-device "mouse" "version" "0x0340") +(config-device "mouse" "serial" "0x0") + + +(add-station "mouse" "mouse-station" 0) +(add-mapping "mouse" "mouse-station" EV_REL REL_X STATION_VALUE 0) +(add-mapping "mouse" "mouse-station" EV_REL REL_Y STATION_VALUE 1) + +(define (dump-mouse) + (display "mouse values: ") + (display (get-values "mouse-station"))(newline) + ) + +(start-device "mouse") diff --git a/avango-unittest/CMakeLists.txt b/avango-unittest/CMakeLists.txt new file mode 100644 index 00000000..d7432686 --- /dev/null +++ b/avango-unittest/CMakeLists.txt @@ -0,0 +1,136 @@ +################################################################ +# Avango +################################################################ +PROJECT(AVANGO CXX) + +# version number +set(AVANGO_MAJOR 1) +set(AVANGO_MINOR 0) +set(AVANGO_PATCH 0) +set(AVANGO_VERSION ${AVANGO_MAJOR}.${AVANGO_MINOR}.${AVANGO_PATCH}) +set(AVANGO_DESCRIPTION "AVANGO") +set(AVANGO_HOMEPAGE "https://github.com/vrsys") +set(AVANGO_EXENAME "AVANGO") +set(AVANGO_PACKAGENAME "AVANGO") + +# We require at least version 2.8.0 +cmake_minimum_required(VERSION 2.8.0) + +if (UNIX) + find_package(PkgConfig) +endif(UNIX) + +# Location where cmake first looks for modules. +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) + +################################################################ +# Configure and find libraries +################################################################ +set(GLOBAL_EXT_DIR ${AVANGO_SOURCE_DIR}/externals) + +MESSAGE(${GLOBAL_EXT_DIR}) + +if (UNIX) + pkg_check_modules(GL REQUIRED gl) +endif (UNIX) + +include(find_compiler) +include(find_boost) + +set(LIBRARIES + ${BOOST_LIBRARIES} + ${GL_LIBRARIES} +) + +set(LIB_PATHS + ${GL_LIBRARY_DIRS} + ${BOOST_LIBRARY_DIRS} +) + +set(INCLUDE_PATHS + ${CMAKE_CURRENT_SOURCE_DIR}/build + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${BOOST_INCLUDE_DIRS} + ${GL_INCLUDE_DIRS} +) + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + +################################################################ +# preprocessor configuration +################################################################ +IF (UNIX) + set(CMAKE_CXX_FLAGS_RELEASE "-s -O4 --std=c++0x -fpermissive") + set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall --std=c++0x -fpermissive") +ELSEIF(MSVC) + set(CMAKE_CXX_FLAGS_RELEASE "-D _SECURE_SCL=0 -D _SCL_SECURE_NO_WARNINGS -D _CRT_SECURE_NO_DEPRECATE /MD /MP") + set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG /MDd /Zi") +ENDIF(UNIX) + +################################################################ +# Avango Configuration +################################################################ +SET (AVANGO_VERSION_MAJOR "1" CACHE STRING "Major version of AvangoNG.") +SET (AVANGO_VERSION_MINOR "90" CACHE STRING "Minor version of AvangoNG.") +SET (AVANGO_VERSION_MAINT "0" CACHE STRING "Maintenance version of AvangoNG.") + +SET (AVANGO_DAEMON_DEBUG "false" CACHE BOOL "Enable Daemon debugging") +SET (AVANGO_DAEMON_VRPN_SUPPORT "false" CACHE BOOL "Enable VRPN support") +SET (AVANGO_DISTRIBUTION_SUPPORT "false" CACHE BOOL "Set to enable distribution support.") +SET (AVANGO_ZMQ_DISTRIBUTION_SUPPORT "false" CACHE BOOL "Set to use ZMQ for distribution.") +SET (AVANGO_PCL_SUPPORT "true" CACHE BOOL "Use PCL.") +SET (AVANGO_LOG_LEVEL "WARN" CACHE STRING "Set AvangoNG log level: FATAL, ERROR, WARN, INFO, DEBUG, TRACE") +SET (AVANGO_UNITTESTS "false" CACHE BOOL "Compile Unittests for Avango.") + +# enable daemon debugging +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_DAEMON_DEBUG") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_DAEMON_VRPN_SUPPORT=${AVANGO_DAEMON_VRPN_SUPPORT}") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_DISTRIBUTION_SUPPORT=${AVANGO_DISTRIBUTION_SUPPORT}") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_ZMQ_DISTRIBUTION_SUPPORT=${AVANGO_ZMQ_DISTRIBUTION_SUPPORT}") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_PCL_SUPPORT=${AVANGO_PCL_SUPPORT}") + + +# add DEBUG flag for debug built +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D DEFINE_AVANGO_DEBUG=1") + +# set debug log level and version strings +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_LOG_LEVEL=${AVANGO_LOG_LEVEL}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_VERSION_MAJOR=${AVANGO_VERSION_MAJOR}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_VERSION_MINOR=${AVANGO_VERSION_MINOR}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D _AVANGO_VERSION_MAINT=${AVANGO_VERSION_MAINT}") + +IF (MSVC) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D AV_LIBRARY") +ENDIF (MSVC) + + +################################################################ +# Create libraries +################################################################ + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) +set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) + +add_subdirectory(avango-core) +add_subdirectory(avango-daemon) +#add_subdirectory(avango-python) + +################################################################ +# Summary +################################################################ + +message( "" ) +message( "Summary:" ) +message( " build type: ${CMAKE_BUILD_TYPE}" ) +message( "" ) +message( " boost:" ) +message( " library: ${BOOST_LIBRARIES}" ) +message( " library path: ${BOOST_LIBRARY_DIRS}" ) +message( " include: ${BOOST_INCLUDE_DIRS}" ) +message( "" ) +message( " gl:" ) +message( " library: ${GL_LIBRARIES}" ) +message( " include: ${GL_INCLUDE_DIRS}" ) +message( "" ) diff --git a/avango-unittest/dist/pkg-config/avango-unittest.pc.in b/avango-unittest/dist/pkg-config/avango-unittest.pc.in new file mode 100644 index 00000000..aede2d04 --- /dev/null +++ b/avango-unittest/dist/pkg-config/avango-unittest.pc.in @@ -0,0 +1,10 @@ +prefix=%(PREFIX)s +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: Avango UnitTest++ +Description: Avango build of the UnitTest++ framework. +Version: %(AVANGO_UNITTEST_VERSION)s +URL: http://www.avango.org +Libs: -L${libdir} -lavangoUnitTest++ +Cflags: -I${includedir} diff --git a/avango-unittest/include/avango/UnitTest++/AssertException.h b/avango-unittest/include/avango/UnitTest++/AssertException.h new file mode 100644 index 00000000..e04d450a --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/AssertException.h @@ -0,0 +1,28 @@ +#ifndef UNITTEST_ASSERTEXCEPTION_H +#define UNITTEST_ASSERTEXCEPTION_H + +#include + + +namespace UnitTest { + +class AssertException : public std::exception +{ +public: + AssertException(char const* description, char const* filename, int lineNumber); + virtual ~AssertException() throw(); + + virtual char const* what() const throw(); + + char const* Filename() const; + int LineNumber() const; + +private: + char m_description[512]; + char m_filename[256]; + int m_lineNumber; +}; + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/CheckMacros.h b/avango-unittest/include/avango/UnitTest++/CheckMacros.h new file mode 100644 index 00000000..2d499cc8 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/CheckMacros.h @@ -0,0 +1,102 @@ +#ifndef UNITTEST_CHECKMACROS_H +#define UNITTEST_CHECKMACROS_H + +#include "Checks.h" +#include "AssertException.h" +#include "MemoryOutStream.h" +#include "TestDetails.h" + +#ifdef CHECK + #error UnitTest++ redefines CHECK +#endif + + +#define CHECK(value) \ + do \ + { \ + try { \ + if (!UnitTest::Check(value)) \ + testResults_.OnTestFailure( UnitTest::TestDetails(m_details, __LINE__), #value); \ + } \ + catch (...) { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception in CHECK(" #value ")"); \ + } \ + } while (0) + +#define CHECK_EQUAL(expected, actual) \ + do \ + { \ + try { \ + UnitTest::CheckEqual(testResults_, expected, actual, UnitTest::TestDetails(m_details, __LINE__)); \ + } \ + catch (...) { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception in CHECK_EQUAL(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_CLOSE(expected, actual, tolerance) \ + do \ + { \ + try { \ + UnitTest::CheckClose(testResults_, expected, actual, tolerance, UnitTest::TestDetails(m_details, __LINE__)); \ + } \ + catch (...) { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception in CHECK_CLOSE(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_ARRAY_EQUAL(expected, actual, count) \ + do \ + { \ + try { \ + UnitTest::CheckArrayEqual(testResults_, expected, actual, count, UnitTest::TestDetails(m_details, __LINE__)); \ + } \ + catch (...) { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception in CHECK_ARRAY_EQUAL(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_ARRAY_CLOSE(expected, actual, count, tolerance) \ + do \ + { \ + try { \ + UnitTest::CheckArrayClose(testResults_, expected, actual, count, tolerance, UnitTest::TestDetails(m_details, __LINE__)); \ + } \ + catch (...) { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"); \ + } \ + } while (0) + +#define CHECK_ARRAY2D_CLOSE(expected, actual, rows, columns, tolerance) \ + do \ + { \ + try { \ + UnitTest::CheckArray2DClose(testResults_, expected, actual, rows, columns, tolerance, UnitTest::TestDetails(m_details, __LINE__)); \ + } \ + catch (...) { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception in CHECK_ARRAY_CLOSE(" #expected ", " #actual ")"); \ + } \ + } while (0) + + +#define CHECK_THROW(expression, ExpectedExceptionType) \ + do \ + { \ + bool caught_ = false; \ + try { expression; } \ + catch (ExpectedExceptionType const&) { caught_ = true; } \ + catch (...) {} \ + if (!caught_) \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), "Expected exception: \"" #ExpectedExceptionType "\" not thrown"); \ + } while(0) + +#define CHECK_ASSERT(expression) \ + CHECK_THROW(expression, UnitTest::AssertException); + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/Checks.h b/avango-unittest/include/avango/UnitTest++/Checks.h new file mode 100644 index 00000000..b470b628 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/Checks.h @@ -0,0 +1,146 @@ +#ifndef UNITTEST_CHECKS_H +#define UNITTEST_CHECKS_H + +#include "Config.h" +#include "TestResults.h" +#include "MemoryOutStream.h" + +namespace UnitTest { + + +template< typename Value > +bool Check(Value const value) +{ + return !!value; // doing double negative to avoid silly VS warnings +} + + +template< typename Expected, typename Actual > +void CheckEqual(TestResults& results, Expected const expected, Actual const actual, TestDetails const& details) +{ + if (!(expected == actual)) + { + UnitTest::MemoryOutStream stream; + stream << "Expected " << expected << " but was " << actual; + + results.OnTestFailure(details, stream.GetText()); + } +} + +void CheckEqual(TestResults& results, char const* expected, char const* actual, TestDetails const& details); + +void CheckEqual(TestResults& results, char* expected, char* actual, TestDetails const& details); + +void CheckEqual(TestResults& results, char* expected, char const* actual, TestDetails const& details); + +void CheckEqual(TestResults& results, char const* expected, char* actual, TestDetails const& details); + +template< typename Expected, typename Actual, typename Tolerance > +bool AreClose(Expected const expected, Actual const actual, Tolerance const tolerance) +{ + return (actual >= (expected - tolerance)) && (actual <= (expected + tolerance)); +} + +template< typename Expected, typename Actual, typename Tolerance > +void CheckClose(TestResults& results, Expected const expected, Actual const actual, Tolerance const tolerance, + TestDetails const& details) +{ + if (!AreClose(expected, actual, tolerance)) + { + UnitTest::MemoryOutStream stream; + stream << "Expected " << expected << " +/- " << tolerance << " but was " << actual; + + results.OnTestFailure(details, stream.GetText()); + } +} + + +template< typename Expected, typename Actual > +void CheckArrayEqual(TestResults& results, Expected const expected, Actual const actual, + int const count, TestDetails const& details) +{ + bool equal = true; + for (int i = 0; i < count; ++i) + equal &= (expected[i] == actual[i]); + + if (!equal) + { + UnitTest::MemoryOutStream stream; + stream << "Expected [ "; + for (int i = 0; i < count; ++i) + stream << expected[i] << " "; + stream << "] but was [ "; + for (int i = 0; i < count; ++i) + stream << actual[i] << " "; + stream << "]"; + + results.OnTestFailure(details, stream.GetText()); + } +} + +template< typename Expected, typename Actual, typename Tolerance > +bool ArrayAreClose(Expected const expected, Actual const actual, int const count, Tolerance const tolerance) +{ + bool equal = true; + for (int i = 0; i < count; ++i) + equal &= AreClose(expected[i], actual[i], tolerance); + return equal; +} + +template< typename Expected, typename Actual, typename Tolerance > +void CheckArrayClose(TestResults& results, Expected const expected, Actual const actual, + int const count, Tolerance const tolerance, TestDetails const& details) +{ + bool equal = ArrayAreClose(expected, actual, count, tolerance); + + if (!equal) + { + UnitTest::MemoryOutStream stream; + stream << "Expected [ "; + for (int i = 0; i < count; ++i) + stream << expected[i] << " "; + stream << "] +/- " << tolerance << " but was [ "; + for (int i = 0; i < count; ++i) + stream << actual[i] << " "; + stream << "]"; + + results.OnTestFailure(details, stream.GetText()); + } +} + +template< typename Expected, typename Actual, typename Tolerance > +void CheckArray2DClose(TestResults& results, Expected const expected, Actual const actual, + int const rows, int const columns, Tolerance const tolerance, TestDetails const& details) +{ + bool equal = true; + for (int i = 0; i < rows; ++i) + equal &= ArrayAreClose(expected[i], actual[i], columns, tolerance); + + if (!equal) + { + UnitTest::MemoryOutStream stream; + stream << "Expected [ "; + for (int i = 0; i < rows; ++i) + { + stream << "[ "; + for (int j = 0; j < columns; ++j) + stream << expected[i][j] << " "; + stream << "] "; + } + stream << "] +/- " << tolerance << " but was [ "; + for (int i = 0; i < rows; ++i) + { + stream << "[ "; + for (int j = 0; j < columns; ++j) + stream << actual[i][j] << " "; + stream << "] "; + } + stream << "]"; + + results.OnTestFailure(details, stream.GetText()); + } +} + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/Config.h b/avango-unittest/include/avango/UnitTest++/Config.h new file mode 100644 index 00000000..db423d42 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/Config.h @@ -0,0 +1,25 @@ +#ifndef UNITTEST_CONFIG_H +#define UNITTEST_CONFIG_H + +// Standard defines documented here: http://predef.sourceforge.net + +#if defined _MSC_VER + #pragma warning(disable:4127) // conditional expression is constant + #pragma warning(disable:4702) // unreachable code + #pragma warning(disable:4722) // destructor never returns, potential memory leak +#endif + +#if defined(unix) || defined(__unix__) || defined(__unix) || defined(linux) || \ + defined(__APPLE__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) + #define UNITTEST_POSIX +#endif + +#if defined (__MINGW32__) + #define UNITTEST_MINGW +#endif + +// by default, MemoryOutStream is implemented in terms of std::ostringstream. +// uncomment this line to use the custom MemoryOutStream (no deps on std::ostringstream). +//#define UNITTEST_USE_CUSTOM_STREAMS + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/DeferredTestReporter.h b/avango-unittest/include/avango/UnitTest++/DeferredTestReporter.h new file mode 100644 index 00000000..026ed051 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/DeferredTestReporter.h @@ -0,0 +1,28 @@ +#ifndef UNITTEST_DEFERREDTESTREPORTER_H +#define UNITTEST_DEFERREDTESTREPORTER_H + +#include "TestReporter.h" +#include "DeferredTestResult.h" + +#include + +namespace UnitTest +{ + +class DeferredTestReporter : public TestReporter +{ +public: + virtual void ReportTestStart(TestDetails const& details); + virtual void ReportFailure(TestDetails const& details, char const* failure); + virtual void ReportTestFinish(TestDetails const& details, float secondsElapsed); + + typedef std::vector< DeferredTestResult > DeferredTestResultList; + DeferredTestResultList& GetResults(); + +private: + DeferredTestResultList m_results; +}; + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/DeferredTestResult.h b/avango-unittest/include/avango/UnitTest++/DeferredTestResult.h new file mode 100644 index 00000000..6cca77c7 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/DeferredTestResult.h @@ -0,0 +1,29 @@ +#ifndef UNITTEST_DEFERREDTESTRESULT_H +#define UNITTEST_DEFERREDTESTRESULT_H + +#include +#include + +namespace UnitTest +{ + +struct DeferredTestResult +{ + DeferredTestResult(); + DeferredTestResult(char const* suite, char const* test); + + std::string suiteName; + std::string testName; + std::string failureFile; + + typedef std::pair< int, std::string > Failure; + typedef std::vector< Failure > FailureVec; + FailureVec failures; + + float timeElapsed; + bool failed; +}; + +} + +#endif //UNITTEST_DEFERREDTESTRESULT_H diff --git a/avango-unittest/include/avango/UnitTest++/MemoryOutStream.h b/avango-unittest/include/avango/UnitTest++/MemoryOutStream.h new file mode 100644 index 00000000..e03227e7 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/MemoryOutStream.h @@ -0,0 +1,67 @@ +#ifndef UNITTEST_MEMORYOUTSTREAM_H +#define UNITTEST_MEMORYOUTSTREAM_H + +#include "Config.h" + +#ifndef UNITTEST_USE_CUSTOM_STREAMS + +#include + +namespace UnitTest +{ + +class MemoryOutStream : public std::ostringstream +{ +public: + MemoryOutStream() {} + char const* GetText() const; + +private: + MemoryOutStream(MemoryOutStream const&); + void operator =(MemoryOutStream const&); + + mutable std::string m_text; +}; + +} + +#else + +#include + +namespace UnitTest +{ + +class MemoryOutStream +{ +public: + explicit MemoryOutStream(int const size = 256); + ~MemoryOutStream(); + + char const* GetText() const; + + MemoryOutStream& operator << (char const* txt); + MemoryOutStream& operator << (int n); + MemoryOutStream& operator << (long n); + MemoryOutStream& operator << (unsigned long n); + MemoryOutStream& operator << (float f); + MemoryOutStream& operator << (double d); + MemoryOutStream& operator << (void const* p); + MemoryOutStream& operator << (unsigned int s); + + enum { GROW_CHUNK_SIZE = 32 }; + int GetCapacity() const; + +private: + void operator= (MemoryOutStream const&); + void GrowBuffer(int capacity); + + int m_capacity; + char* m_buffer; +}; + +} + +#endif + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/Posix/SignalTranslator.h b/avango-unittest/include/avango/UnitTest++/Posix/SignalTranslator.h new file mode 100644 index 00000000..dfa0d116 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/Posix/SignalTranslator.h @@ -0,0 +1,42 @@ +#ifndef UNITTEST_SIGNALTRANSLATOR_H +#define UNITTEST_SIGNALTRANSLATOR_H + +#include +#include + +namespace UnitTest { + +class SignalTranslator +{ +public: + SignalTranslator(); + ~SignalTranslator(); + + static sigjmp_buf* s_jumpTarget; + +private: + sigjmp_buf m_currentJumpTarget; + sigjmp_buf* m_oldJumpTarget; + + struct sigaction m_old_SIGFPE_action; + struct sigaction m_old_SIGTRAP_action; + struct sigaction m_old_SIGSEGV_action; + struct sigaction m_old_SIGBUS_action; + struct sigaction m_old_SIGABRT_action; + struct sigaction m_old_SIGALRM_action; +}; + +#ifdef SOLARIS + #define UNITTEST_EXTENSION +#else + #define UNITTEST_EXTENSION __extension__ +#endif + +#define UNITTEST_THROW_SIGNALS \ + UnitTest::SignalTranslator sig; \ + if (UNITTEST_EXTENSION sigsetjmp(*UnitTest::SignalTranslator::s_jumpTarget, 1) != 0) \ + throw ("Unhandled system exception"); + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/Posix/TimeHelpers.h b/avango-unittest/include/avango/UnitTest++/Posix/TimeHelpers.h new file mode 100644 index 00000000..fdc84288 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/Posix/TimeHelpers.h @@ -0,0 +1,28 @@ +#ifndef UNITTEST_TIMEHELPERS_H +#define UNITTEST_TIMEHELPERS_H + +#include + +namespace UnitTest { + +class Timer +{ +public: + Timer(); + void Start(); + int GetTimeInMs() const; + +private: + struct timeval m_startTime; +}; + + +namespace TimeHelpers +{ +void SleepMs (int ms); +} + + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/ReportAssert.h b/avango-unittest/include/avango/UnitTest++/ReportAssert.h new file mode 100644 index 00000000..d4dd8641 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/ReportAssert.h @@ -0,0 +1,10 @@ +#ifndef UNITTEST_ASSERT_H +#define UNITTEST_ASSERT_H + +namespace UnitTest { + +void ReportAssert(char const* description, char const* filename, int lineNumber); + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/Test.h b/avango-unittest/include/avango/UnitTest++/Test.h new file mode 100644 index 00000000..458c75c6 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/Test.h @@ -0,0 +1,34 @@ +#ifndef UNITTEST_TEST_H +#define UNITTEST_TEST_H + +#include "TestDetails.h" + +namespace UnitTest { + +class TestResults; +class TestList; + +class Test +{ +public: + Test(char const* testName, char const* suiteName = "DefaultSuite", char const* filename = "", int lineNumber = 0); + virtual ~Test(); + void Run(TestResults& testResults) const; + + TestDetails const m_details; + Test* next; + mutable bool m_timeConstraintExempt; + + static TestList& GetTestList(); + +private: + virtual void RunImpl(TestResults& testResults_) const; + + Test(Test const&); + Test& operator =(Test const&); +}; + + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestDetails.h b/avango-unittest/include/avango/UnitTest++/TestDetails.h new file mode 100644 index 00000000..eae0e71e --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestDetails.h @@ -0,0 +1,24 @@ +#ifndef UNITTEST_TESTDETAILS_H +#define UNITTEST_TESTDETAILS_H + +namespace UnitTest { + +class TestDetails +{ +public: + TestDetails(char const* testName, char const* suiteName, char const* filename, int lineNumber); + TestDetails(const TestDetails& details, int lineNumber); + + char const* const suiteName; + char const* const testName; + char const* const filename; + int const lineNumber; + + TestDetails(TestDetails const&); // Why is it public? --> http://gcc.gnu.org/bugs.html#cxx_rvalbind +private: + TestDetails& operator=(TestDetails const&); +}; + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestList.h b/avango-unittest/include/avango/UnitTest++/TestList.h new file mode 100644 index 00000000..14b978ab --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestList.h @@ -0,0 +1,32 @@ +#ifndef UNITTEST_TESTLIST_H +#define UNITTEST_TESTLIST_H + + +namespace UnitTest { + +class Test; + +class TestList +{ +public: + TestList(); + void Add (Test* test); + + const Test* GetHead() const; + +private: + Test* m_head; + Test* m_tail; +}; + + +class ListAdder +{ +public: + ListAdder(TestList& list, Test* test); +}; + +} + + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestMacros.h b/avango-unittest/include/avango/UnitTest++/TestMacros.h new file mode 100644 index 00000000..09ecc6bb --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestMacros.h @@ -0,0 +1,99 @@ +#ifndef UNITTEST_TESTMACROS_H +#define UNITTEST_TESTMACROS_H + +#include "Config.h" + +#ifndef UNITTEST_POSIX + #define UNITTEST_THROW_SIGNALS +#else + #include "Posix/SignalTranslator.h" +#endif + +#ifdef TEST + #error UnitTest++ redefines TEST +#endif + +#define SUITE(Name) \ + namespace Name { \ + namespace UnitTestSuite { \ + inline char const* GetSuiteName () { \ + return #Name ; \ + } \ + } \ + } \ + namespace Name + +#define TEST_EX(Name, List) \ + class Test##Name : public UnitTest::Test \ + { \ + public: \ + Test##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + private: \ + virtual void RunImpl(UnitTest::TestResults& testResults_) const; \ + } test##Name##Instance; \ + \ + UnitTest::ListAdder adder##Name (List, &test##Name##Instance); \ + \ + void Test##Name::RunImpl(UnitTest::TestResults& testResults_) const + + +#define TEST(Name) TEST_EX(Name, UnitTest::Test::GetTestList()) + + +#define TEST_FIXTURE_EX(Fixture, Name, List) \ + class Fixture##Name##Helper : public Fixture \ + { \ + public: \ + Fixture##Name##Helper(UnitTest::TestDetails const& details) : m_details(details) {} \ + void RunTest(UnitTest::TestResults& testResults_); \ + UnitTest::TestDetails const& m_details; \ + private: \ + Fixture##Name##Helper(Fixture##Name##Helper const&); \ + Fixture##Name##Helper& operator =(Fixture##Name##Helper const&); \ + }; \ + \ + class Test##Fixture##Name : public UnitTest::Test \ + { \ + public: \ + Test##Fixture##Name() : Test(#Name, UnitTestSuite::GetSuiteName(), __FILE__, __LINE__) {} \ + private: \ + virtual void RunImpl(UnitTest::TestResults& testResults_) const; \ + } test##Fixture##Name##Instance; \ + \ + UnitTest::ListAdder adder##Fixture##Name (List, &test##Fixture##Name##Instance); \ + \ + void Test##Fixture##Name::RunImpl(UnitTest::TestResults& testResults_) const \ + { \ + bool ctorOk = false; \ + try { \ + Fixture##Name##Helper fixtureHelper(m_details); \ + ctorOk = true; \ + try { \ + UNITTEST_THROW_SIGNALS; \ + fixtureHelper.RunTest(testResults_); \ + } catch (UnitTest::AssertException const& e) { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details.testName, m_details.suiteName, e.Filename(), e.LineNumber()), e.what()); \ + } catch (std::exception const& e) { \ + UnitTest::MemoryOutStream stream; \ + stream << "Unhandled exception: " << e.what(); \ + testResults_.OnTestFailure(m_details, stream.GetText()); \ + } catch (...) { testResults_.OnTestFailure(m_details, "Unhandled exception: Crash!"); } \ + } \ + catch (...) { \ + if (ctorOk) \ + { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while destroying fixture " #Fixture); \ + } \ + else \ + { \ + testResults_.OnTestFailure(UnitTest::TestDetails(m_details, __LINE__), \ + "Unhandled exception while constructing fixture " #Fixture); \ + } \ + } \ + } \ + void Fixture##Name##Helper::RunTest(UnitTest::TestResults& testResults_) + +#define TEST_FIXTURE(Fixture,Name) TEST_FIXTURE_EX(Fixture, Name, UnitTest::Test::GetTestList()) + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestReporter.h b/avango-unittest/include/avango/UnitTest++/TestReporter.h new file mode 100644 index 00000000..5a2f404c --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestReporter.h @@ -0,0 +1,20 @@ +#ifndef UNITTEST_TESTREPORTER_H +#define UNITTEST_TESTREPORTER_H + +namespace UnitTest { + +class TestDetails; + +class TestReporter +{ +public: + virtual ~TestReporter(); + + virtual void ReportTestStart(TestDetails const& test) = 0; + virtual void ReportFailure(TestDetails const& test, char const* failure) = 0; + virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed) = 0; + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) = 0; +}; + +} +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestReporterStdout.h b/avango-unittest/include/avango/UnitTest++/TestReporterStdout.h new file mode 100644 index 00000000..eacbba31 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestReporterStdout.h @@ -0,0 +1,19 @@ +#ifndef UNITTEST_TESTREPORTERSTDOUT_H +#define UNITTEST_TESTREPORTERSTDOUT_H + +#include "TestReporter.h" + +namespace UnitTest { + +class TestReporterStdout : public TestReporter +{ +private: + virtual void ReportTestStart(TestDetails const& test); + virtual void ReportFailure(TestDetails const& test, char const* failure); + virtual void ReportTestFinish(TestDetails const& test, float secondsElapsed); + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); +}; + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestResults.h b/avango-unittest/include/avango/UnitTest++/TestResults.h new file mode 100644 index 00000000..8ef7fdad --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestResults.h @@ -0,0 +1,36 @@ +#ifndef UNITTEST_TESTRESULTS_H +#define UNITTEST_TESTRESULTS_H + +namespace UnitTest { + +class TestReporter; +class TestDetails; + +class TestResults +{ +public: + explicit TestResults(TestReporter* reporter = 0); + + void OnTestStart(TestDetails const& test); + void OnTestFailure(TestDetails const& test, char const* failure); + void OnTestFinish(TestDetails const& test, float secondsElapsed); + + int GetTotalTestCount() const; + int GetFailedTestCount() const; + int GetFailureCount() const; + +private: + TestReporter* m_testReporter; + int m_totalTestCount; + int m_failedTestCount; + int m_failureCount; + + bool m_currentTestFailed; + + TestResults(TestResults const&); + TestResults& operator =(TestResults const&); +}; + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestRunner.h b/avango-unittest/include/avango/UnitTest++/TestRunner.h new file mode 100644 index 00000000..8b9934a7 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestRunner.h @@ -0,0 +1,17 @@ +#ifndef UNITTEST_TESTRUNNER_H +#define UNITTEST_TESTRUNNER_H + + +namespace UnitTest { + +class TestReporter; +class TestList; + + +int RunAllTests(); +int RunAllTests(TestReporter& reporter, TestList const& list, char const* suiteName, int maxTestTimeInMs = 0); + +} + + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TestSuite.h b/avango-unittest/include/avango/UnitTest++/TestSuite.h new file mode 100644 index 00000000..dd3717e1 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TestSuite.h @@ -0,0 +1,14 @@ +#ifndef UNITTEST_TESTSUITE_H +#define UNITTEST_TESTSUITE_H + +namespace UnitTestSuite { + + inline char const* GetSuiteName () + { + return "DefaultSuite"; + } + +} + +#endif + diff --git a/avango-unittest/include/avango/UnitTest++/TimeConstraint.h b/avango-unittest/include/avango/UnitTest++/TimeConstraint.h new file mode 100644 index 00000000..8451c66d --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TimeConstraint.h @@ -0,0 +1,34 @@ +#ifndef UNITTEST_TIMECONSTRAINT_H +#define UNITTEST_TIMECONSTRAINT_H + +#include "TimeHelpers.h" + +namespace UnitTest { + +class TestResults; +class TestDetails; + +class TimeConstraint +{ +public: + TimeConstraint(int ms, TestResults& result, TestDetails const& details); + ~TimeConstraint(); + +private: + void operator=(TimeConstraint const&); + TimeConstraint(TimeConstraint const&); + + Timer m_timer; + TestResults& m_result; + TestDetails const& m_details; + int const m_maxMs; +}; + +#define UNITTEST_TIME_CONSTRAINT(ms) \ + UnitTest::TimeConstraint unitTest__timeConstraint__(ms, testResults_, UnitTest::TestDetails(m_details, __LINE__)) + +#define UNITTEST_TIME_CONSTRAINT_EXEMPT() do { m_timeConstraintExempt = true; } while (0) + +} + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/TimeHelpers.h b/avango-unittest/include/avango/UnitTest++/TimeHelpers.h new file mode 100644 index 00000000..f34ed008 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/TimeHelpers.h @@ -0,0 +1,7 @@ +#include "Config.h" + +#if defined UNITTEST_POSIX + #include "Posix/TimeHelpers.h" +#else + #include "Win32/TimeHelpers.h" +#endif diff --git a/avango-unittest/include/avango/UnitTest++/UnitTest++.h b/avango-unittest/include/avango/UnitTest++/UnitTest++.h new file mode 100644 index 00000000..019f80a8 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/UnitTest++.h @@ -0,0 +1,17 @@ +#ifndef UNITTESTCPP_H +#define UNITTESTCPP_H + +#include "Config.h" +#include "Test.h" +#include "TestList.h" +#include "TestSuite.h" +#include "TestResults.h" + +#include +#include "TestMacros.h" + +#include "CheckMacros.h" +#include "TestRunner.h" +#include "TimeConstraint.h" + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/Win32/TimeHelpers.h b/avango-unittest/include/avango/UnitTest++/Win32/TimeHelpers.h new file mode 100644 index 00000000..56e30d55 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/Win32/TimeHelpers.h @@ -0,0 +1,48 @@ +#ifndef UNITTEST_TIMEHELPERS_H +#define UNITTEST_TIMEHELPERS_H + +#include "../Config.h" + + +#ifdef UNITTEST_MINGW + #ifndef __int64 + #define __int64 long long + #endif +#endif + +namespace UnitTest { + +class Timer +{ +public: + Timer(); + void Start(); + int GetTimeInMs() const; + +private: + __int64 GetTime() const; + + void* m_threadId; + +#if defined(_WIN64) + unsigned __int64 m_processAffinityMask; +#else + unsigned long m_processAffinityMask; +#endif + + __int64 m_startTime; + __int64 m_frequency; +}; + + +namespace TimeHelpers +{ +void SleepMs (int ms); +} + + +} + + + +#endif diff --git a/avango-unittest/include/avango/UnitTest++/XmlTestReporter.h b/avango-unittest/include/avango/UnitTest++/XmlTestReporter.h new file mode 100644 index 00000000..884123b1 --- /dev/null +++ b/avango-unittest/include/avango/UnitTest++/XmlTestReporter.h @@ -0,0 +1,34 @@ +#ifndef UNITTEST_XMLTESTREPORTER_H +#define UNITTEST_XMLTESTREPORTER_H + +#include "DeferredTestReporter.h" + +#include + +namespace UnitTest +{ + +class XmlTestReporter : public DeferredTestReporter +{ +public: + explicit XmlTestReporter(std::ostream& ostream); + + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + +private: + XmlTestReporter(XmlTestReporter const&); + XmlTestReporter& operator=(XmlTestReporter const&); + + void AddXmlElement(std::ostream& os, char const* encoding); + void BeginResults(std::ostream& os, int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed); + void EndResults(std::ostream& os); + void BeginTest(std::ostream& os, DeferredTestResult const& result); + void AddFailure(std::ostream& os, DeferredTestResult const& result); + void EndTest(std::ostream& os, DeferredTestResult const& result); + + std::ostream& m_ostream; +}; + +} + +#endif diff --git a/avango-unittest/src/avango/UnitTest++/AssertException.cpp b/avango-unittest/src/avango/UnitTest++/AssertException.cpp new file mode 100644 index 00000000..c3067b29 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/AssertException.cpp @@ -0,0 +1,32 @@ +#include +#include + +namespace UnitTest { + +AssertException::AssertException(char const* description, char const* filename, int const lineNumber) + : m_lineNumber(lineNumber) +{ + std::strcpy(m_description, description); + std::strcpy(m_filename, filename); +} + +AssertException::~AssertException() throw() +{ +} + +char const* AssertException::what() const throw() +{ + return m_description; +} + +char const* AssertException::Filename() const +{ + return m_filename; +} + +int AssertException::LineNumber() const +{ + return m_lineNumber; +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/COPYING b/avango-unittest/src/avango/UnitTest++/COPYING new file mode 100644 index 00000000..9f963085 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/COPYING @@ -0,0 +1,20 @@ +Copyright (c) 2006 Noel Llopis and Charles Nicholson + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/avango-unittest/src/avango/UnitTest++/Checks.cpp b/avango-unittest/src/avango/UnitTest++/Checks.cpp new file mode 100644 index 00000000..2712640e --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/Checks.cpp @@ -0,0 +1,48 @@ +#include +#include + +namespace UnitTest { + +namespace { + +void CheckStringsEqual(TestResults& results, char const* expected, char const* actual, + TestDetails const& details) +{ + if (std::strcmp(expected, actual)) + { + UnitTest::MemoryOutStream stream; + stream << "Expected " << expected << " but was " << actual; + + results.OnTestFailure(details, stream.GetText()); + } +} + +} + + +void CheckEqual(TestResults& results, char const* expected, char const* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + +void CheckEqual(TestResults& results, char* expected, char* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + +void CheckEqual(TestResults& results, char* expected, char const* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + +void CheckEqual(TestResults& results, char const* expected, char* actual, + TestDetails const& details) +{ + CheckStringsEqual(results, expected, actual, details); +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/DeferredTestReporter.cpp b/avango-unittest/src/avango/UnitTest++/DeferredTestReporter.cpp new file mode 100644 index 00000000..9c450019 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/DeferredTestReporter.cpp @@ -0,0 +1,28 @@ +#include +#include + +using namespace UnitTest; + +void DeferredTestReporter::ReportTestStart(TestDetails const& details) +{ + m_results.push_back(DeferredTestResult(details.suiteName, details.testName)); +} + +void DeferredTestReporter::ReportFailure(TestDetails const& details, char const* failure) +{ + DeferredTestResult& r = m_results.back(); + r.failed = true; + r.failures.push_back(DeferredTestResult::Failure(details.lineNumber, failure)); + r.failureFile = details.filename; +} + +void DeferredTestReporter::ReportTestFinish(TestDetails const&, float const secondsElapsed) +{ + DeferredTestResult& r = m_results.back(); + r.timeElapsed = secondsElapsed; +} + +DeferredTestReporter::DeferredTestResultList& DeferredTestReporter::GetResults() +{ + return m_results; +} diff --git a/avango-unittest/src/avango/UnitTest++/DeferredTestResult.cpp b/avango-unittest/src/avango/UnitTest++/DeferredTestResult.cpp new file mode 100644 index 00000000..9cd6e2ec --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/DeferredTestResult.cpp @@ -0,0 +1,26 @@ +#include + +#include + +namespace UnitTest +{ + +DeferredTestResult::DeferredTestResult() + : suiteName("") + , testName("") + , failureFile("") + , timeElapsed(0.0f) + , failed(false) +{ +} + +DeferredTestResult::DeferredTestResult(char const* suite, char const* test) + : suiteName(suite) + , testName(test) + , failureFile("") + , timeElapsed(0.0f) + , failed(false) +{ +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/MemoryOutStream.cpp b/avango-unittest/src/avango/UnitTest++/MemoryOutStream.cpp new file mode 100644 index 00000000..687a829b --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/MemoryOutStream.cpp @@ -0,0 +1,143 @@ +#include + +#ifndef UNITTEST_USE_CUSTOM_STREAMS + + +namespace UnitTest { + +char const* MemoryOutStream::GetText() const +{ + m_text = this->str(); + return m_text.c_str(); +} + + +} + + +#else + + +#include +#include + +namespace UnitTest { + +namespace { + +template +void FormatToStream(MemoryOutStream& stream, char const* format, ValueType const& value) +{ + char txt[32]; + std::sprintf(txt, format, value); + stream << txt; +} + +int RoundUpToMultipleOfPow2Number (int n, int pow2Number) +{ + return (n + (pow2Number - 1)) & ~(pow2Number - 1); +} + +} + + +MemoryOutStream::MemoryOutStream(int const size) + : m_capacity (0) + , m_buffer (0) + +{ + GrowBuffer(size); +} + +MemoryOutStream::~MemoryOutStream() +{ + delete [] m_buffer; +} + +char const* MemoryOutStream::GetText() const +{ + return m_buffer; +} + +MemoryOutStream& MemoryOutStream::operator << (char const* txt) +{ + int const bytesLeft = m_capacity - (int)std::strlen(m_buffer); + int const bytesRequired = (int)std::strlen(txt) + 1; + + if (bytesRequired > bytesLeft) + { + int const requiredCapacity = bytesRequired + m_capacity - bytesLeft; + GrowBuffer(requiredCapacity); + } + + std::strcat(m_buffer, txt); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (int const n) +{ + FormatToStream(*this, "%i", n); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (long const n) +{ + FormatToStream(*this, "%li", n); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (unsigned long const n) +{ + FormatToStream(*this, "%lu", n); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (float const f) +{ + FormatToStream(*this, "%ff", f); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (void const* p) +{ + FormatToStream(*this, "%p", p); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator << (unsigned int const s) +{ + FormatToStream(*this, "%u", s); + return *this; +} + +MemoryOutStream& MemoryOutStream::operator <<(double const d) +{ + FormatToStream(*this, "%f", d); + return *this; +} + +int MemoryOutStream::GetCapacity() const +{ + return m_capacity; +} + + +void MemoryOutStream::GrowBuffer(int const desiredCapacity) +{ + int const newCapacity = RoundUpToMultipleOfPow2Number(desiredCapacity, GROW_CHUNK_SIZE); + + char* buffer = new char[newCapacity]; + if (m_buffer) + std::strcpy(buffer, m_buffer); + else + std::strcpy(buffer, ""); + + delete [] m_buffer; + m_buffer = buffer; + m_capacity = newCapacity; +} + +} + + +#endif diff --git a/avango-unittest/src/avango/UnitTest++/Posix/SignalTranslator.cpp b/avango-unittest/src/avango/UnitTest++/Posix/SignalTranslator.cpp new file mode 100644 index 00000000..f3f0ef5c --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/Posix/SignalTranslator.cpp @@ -0,0 +1,46 @@ +#include + +namespace UnitTest { + +sigjmp_buf* SignalTranslator::s_jumpTarget = 0; + +namespace { + +void SignalHandler (int sig) +{ + siglongjmp(*SignalTranslator::s_jumpTarget, sig ); +} + +} + + +SignalTranslator::SignalTranslator () +{ + m_oldJumpTarget = s_jumpTarget; + s_jumpTarget = &m_currentJumpTarget; + + struct sigaction action; + action.sa_flags = 0; + action.sa_handler = SignalHandler; + sigemptyset( &action.sa_mask ); + + sigaction( SIGSEGV, &action, &m_old_SIGSEGV_action ); + sigaction( SIGFPE , &action, &m_old_SIGFPE_action ); + sigaction( SIGTRAP, &action, &m_old_SIGTRAP_action ); + sigaction( SIGBUS , &action, &m_old_SIGBUS_action ); + sigaction( SIGILL , &action, &m_old_SIGBUS_action ); +} + +SignalTranslator::~SignalTranslator() +{ + sigaction( SIGILL , &m_old_SIGBUS_action , 0 ); + sigaction( SIGBUS , &m_old_SIGBUS_action , 0 ); + sigaction( SIGTRAP, &m_old_SIGTRAP_action, 0 ); + sigaction( SIGFPE , &m_old_SIGFPE_action , 0 ); + sigaction( SIGSEGV, &m_old_SIGSEGV_action, 0 ); + + s_jumpTarget = m_oldJumpTarget; +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/Posix/TimeHelpers.cpp b/avango-unittest/src/avango/UnitTest++/Posix/TimeHelpers.cpp new file mode 100644 index 00000000..faebc442 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/Posix/TimeHelpers.cpp @@ -0,0 +1,33 @@ +#include +#include + +namespace UnitTest { + +Timer::Timer() +{ + m_startTime.tv_sec = 0; + m_startTime.tv_usec = 0; +} + +void Timer::Start() +{ + gettimeofday(&m_startTime, 0); +} + + +int Timer::GetTimeInMs() const +{ + struct timeval currentTime; + gettimeofday(¤tTime, 0); + int const dsecs = currentTime.tv_sec - m_startTime.tv_sec; + int const dus = currentTime.tv_usec - m_startTime.tv_usec; + return dsecs*1000 + dus/1000; +} + + +void TimeHelpers::SleepMs (int ms) +{ + usleep(ms * 1000); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/README b/avango-unittest/src/avango/UnitTest++/README new file mode 100644 index 00000000..416b7e2c --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/README @@ -0,0 +1,57 @@ +UnitTest++ README +Version: v1.2 +Last update: 2006-10-29 + + +UnitTest++ is free software. You may copy, distribute, and modify it under +the terms of the License contained in the file COPYING distributed +with this package. This license is the same as the MIT/X Consortium +license. + +See src/tests/TestUnitTest++.cpp for usage. + +Authors: +Noel Llopis (llopis@convexhull.com) +Charles Nicholson (cn@cnicholson.net) + +Contributors: +Jim Tilander (jim.tilander@gmail.com) +Kim Grasman (kim@mvps.org) +Jonathan Jansson (lilliemarck@users.sourceforge.net) +Dirck Blaskey (listtarget2@danbala.com) +Rory Driscoll (rorydriscoll@gmail.com) +Dan Lind (podcat@gmail.com) +Matt Kimmel (mattkimmel@gmail.com) -- Submitted with permission from Blue Fang Games +Anthony Moralez (anthony.moralez@gmail.com) +Jeff Dixon + + +Release notes +-------------- + +Version 1.2 (2006-10-29) +- First pass at documentation. +- More detailed error crash catching in fixtures. +- Standard streams used for printing objects under check. This should allow the + use of standard class types such as std::string or other custom classes with + stream operators to ostream. +- Standard streams can be optionally compiled off by defining UNITTEST_USE_CUSTOM_STREAMS + in Config.h +- Added named test suites +- Added CHECK_ARRAY2D_CLOSE +- Posix library name is libUnitTest++.a now +- Floating point numbers are postfixed with f in the failure reports + +Version 1.1 (2006-04-18) +- CHECK macros do not have side effects even if one of the parameters changes state +- Removed CHECK_ARRAY_EQUAL (too similar to CHECK_ARRAY_CLOSE) +- Added local and global time constraints +- Removed dependencies on strstream +- Improved Posix signal to exception translator +- Failing tests are added to Visual Studio's error list +- Fixed Visual Studio projects to work with spaces in directories + + +Version 1.0 (2006-03-15) +- Initial release + diff --git a/avango-unittest/src/avango/UnitTest++/ReportAssert.cpp b/avango-unittest/src/avango/UnitTest++/ReportAssert.cpp new file mode 100644 index 00000000..3c090ef0 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/ReportAssert.cpp @@ -0,0 +1,12 @@ +#include + +#include + +namespace UnitTest { + +void ReportAssert(char const* description, char const* filename, int const lineNumber) +{ + throw AssertException(description, filename, lineNumber); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/Test.cpp b/avango-unittest/src/avango/UnitTest++/Test.cpp new file mode 100644 index 00000000..28f8133c --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/Test.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include + +#ifdef UNITTEST_POSIX + #include +#endif + +namespace UnitTest { + +TestList& Test::GetTestList() +{ + static TestList s_list; + return s_list; +} + +Test::Test(char const* testName, char const* suiteName, char const* filename, int const lineNumber) + : m_details(testName, suiteName, filename, lineNumber) + , next(0) + , m_timeConstraintExempt(false) +{ +} + +Test::~Test() +{ +} + +void Test::Run(TestResults& testResults) const +{ + try + { +#ifdef UNITTEST_POSIX + UNITTEST_THROW_SIGNALS +#endif + RunImpl(testResults); + } + catch (AssertException const& e) + { + testResults.OnTestFailure( TestDetails(m_details.testName, m_details.suiteName, e.Filename(), e.LineNumber()), e.what()); + } + catch (std::exception const& e) + { + MemoryOutStream stream; + stream << "Unhandled exception: " << e.what(); + testResults.OnTestFailure(m_details, stream.GetText()); + } + catch (...) + { + testResults.OnTestFailure(m_details, "Unhandled exception: Crash!"); + } +} + + +void Test::RunImpl(TestResults&) const +{ +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/TestDetails.cpp b/avango-unittest/src/avango/UnitTest++/TestDetails.cpp new file mode 100644 index 00000000..97f91984 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/TestDetails.cpp @@ -0,0 +1,22 @@ +#include + +namespace UnitTest { + +TestDetails::TestDetails(char const* testName_, char const* suiteName_, char const* filename_, int lineNumber_) + : suiteName(suiteName_) + , testName(testName_) + , filename(filename_) + , lineNumber(lineNumber_) +{ +} + +TestDetails::TestDetails(const TestDetails& details, int lineNumber_) + : suiteName(details.suiteName) + , testName(details.testName) + , filename(details.filename) + , lineNumber(lineNumber_) +{ +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/TestList.cpp b/avango-unittest/src/avango/UnitTest++/TestList.cpp new file mode 100644 index 00000000..1378b154 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/TestList.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include + +namespace UnitTest { + +TestList::TestList() + : m_head(0) + , m_tail(0) +{ +} + +void TestList::Add(Test* test) +{ + if (m_tail == 0) + { + assert(m_head == 0); + m_head = test; + m_tail = test; + } + else + { + m_tail->next = test; + m_tail = test; + } +} + +const Test* TestList::GetHead() const +{ + return m_head; +} + +ListAdder::ListAdder(TestList& list, Test* test) +{ + list.Add(test); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/TestReporter.cpp b/avango-unittest/src/avango/UnitTest++/TestReporter.cpp new file mode 100644 index 00000000..3e182b2c --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/TestReporter.cpp @@ -0,0 +1,10 @@ +#include + +namespace UnitTest { + + +TestReporter::~TestReporter() +{ +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/TestReporterStdout.cpp b/avango-unittest/src/avango/UnitTest++/TestReporterStdout.cpp new file mode 100644 index 00000000..105e8908 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/TestReporterStdout.cpp @@ -0,0 +1,36 @@ +#include +#include + +#include + +namespace UnitTest { + +void TestReporterStdout::ReportFailure(TestDetails const& details, char const* failure) +{ +#ifdef __APPLE__ + char const* const errorFormat = "%s:%d: error: Failure in %s: %s\n"; +#else + char const* const errorFormat = "%s(%d): error: Failure in %s: %s\n"; +#endif + std::printf(errorFormat, details.filename, details.lineNumber, details.testName, failure); +} + +void TestReporterStdout::ReportTestStart(TestDetails const& /*test*/) +{ +} + +void TestReporterStdout::ReportTestFinish(TestDetails const& /*test*/, float) +{ +} + +void TestReporterStdout::ReportSummary(int const totalTestCount, int const failedTestCount, + int const failureCount, float secondsElapsed) +{ + if (failureCount > 0) + std::printf("FAILURE: %d out of %d tests failed (%d failures).\n", failedTestCount, totalTestCount, failureCount); + else + std::printf("Success: %d tests passed.\n", totalTestCount); + std::printf("Test time: %.2f seconds.\n", secondsElapsed); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/TestResults.cpp b/avango-unittest/src/avango/UnitTest++/TestResults.cpp new file mode 100644 index 00000000..c3694a7b --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/TestResults.cpp @@ -0,0 +1,60 @@ +#include +#include + +#include + +namespace UnitTest { + +TestResults::TestResults(TestReporter* testReporter) + : m_testReporter(testReporter) + , m_totalTestCount(0) + , m_failedTestCount(0) + , m_failureCount(0) + , m_currentTestFailed(false) +{ +} + +void TestResults::OnTestStart(TestDetails const& test) +{ + ++m_totalTestCount; + m_currentTestFailed = false; + if (m_testReporter) + m_testReporter->ReportTestStart(test); +} + +void TestResults::OnTestFailure(TestDetails const& test, char const* failure) +{ + ++m_failureCount; + if (!m_currentTestFailed) + { + ++m_failedTestCount; + m_currentTestFailed = true; + } + + if (m_testReporter) + m_testReporter->ReportFailure(test, failure); +} + +void TestResults::OnTestFinish(TestDetails const& test, float secondsElapsed) +{ + if (m_testReporter) + m_testReporter->ReportTestFinish(test, secondsElapsed); +} + +int TestResults::GetTotalTestCount() const +{ + return m_totalTestCount; +} + +int TestResults::GetFailedTestCount() const +{ + return m_failedTestCount; +} + +int TestResults::GetFailureCount() const +{ + return m_failureCount; +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/TestRunner.cpp b/avango-unittest/src/avango/UnitTest++/TestRunner.cpp new file mode 100644 index 00000000..0658d987 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/TestRunner.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace UnitTest { + + +int RunAllTests(TestReporter& reporter, TestList const& list, char const* suiteName, int const maxTestTimeInMs ) +{ + TestResults result(&reporter); + + Timer overallTimer; + overallTimer.Start(); + + Test const* curTest = list.GetHead(); + while (curTest != 0) + { + if (suiteName == 0 || !std::strcmp(curTest->m_details.suiteName, suiteName)) + { + Timer testTimer; + testTimer.Start(); + result.OnTestStart(curTest->m_details); + + curTest->Run(result); + + int const testTimeInMs = testTimer.GetTimeInMs(); + if (maxTestTimeInMs > 0 && testTimeInMs > maxTestTimeInMs && !curTest->m_timeConstraintExempt) + { + MemoryOutStream stream; + stream << "Global time constraint failed. Expected under " << maxTestTimeInMs << + "ms but took " << testTimeInMs << "ms."; + result.OnTestFailure(curTest->m_details, stream.GetText()); + } + result.OnTestFinish(curTest->m_details, testTimeInMs/1000.0f); + } + + curTest = curTest->next; + } + + float const secondsElapsed = overallTimer.GetTimeInMs() / 1000.0f; + reporter.ReportSummary(result.GetTotalTestCount(), result.GetFailedTestCount(), result.GetFailureCount(), secondsElapsed); + + return result.GetFailureCount(); +} + + +int RunAllTests() +{ + TestReporterStdout reporter; + return RunAllTests(reporter, Test::GetTestList(), 0); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/TimeConstraint.cpp b/avango-unittest/src/avango/UnitTest++/TimeConstraint.cpp new file mode 100644 index 00000000..9baf168a --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/TimeConstraint.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +namespace UnitTest { + + +TimeConstraint::TimeConstraint(int ms, TestResults& result, TestDetails const& details) + : m_result(result) + , m_details(details) + , m_maxMs(ms) +{ + m_timer.Start(); +} + +TimeConstraint::~TimeConstraint() +{ + int const totalTimeInMs = m_timer.GetTimeInMs(); + if (totalTimeInMs > m_maxMs) + { + MemoryOutStream stream; + stream << "Time constraint failed. Expected to run test under " << m_maxMs << + "ms but took " << totalTimeInMs << "ms."; + m_result.OnTestFailure(m_details, stream.GetText()); + } +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/Win32/TimeHelpers.cpp b/avango-unittest/src/avango/UnitTest++/Win32/TimeHelpers.cpp new file mode 100644 index 00000000..83d0d934 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/Win32/TimeHelpers.cpp @@ -0,0 +1,46 @@ +#include +#include + +namespace UnitTest { + +Timer::Timer() + : m_startTime(0) +{ + m_threadId = ::GetCurrentThread(); + DWORD_PTR systemMask; + ::GetProcessAffinityMask(GetCurrentProcess(), &m_processAffinityMask, &systemMask); + + ::SetThreadAffinityMask(m_threadId, 1); + ::QueryPerformanceFrequency(reinterpret_cast< LARGE_INTEGER* >(&m_frequency)); + ::SetThreadAffinityMask(m_threadId, m_processAffinityMask); +} + +void Timer::Start() +{ + m_startTime = GetTime(); +} + +int Timer::GetTimeInMs() const +{ + __int64 const elapsedTime = GetTime() - m_startTime; + double const seconds = double(elapsedTime) / double(m_frequency); + return int(seconds * 1000.0f); +} + +__int64 Timer::GetTime() const +{ + LARGE_INTEGER curTime; + ::SetThreadAffinityMask(m_threadId, 1); + ::QueryPerformanceCounter(&curTime); + ::SetThreadAffinityMask(m_threadId, m_processAffinityMask); + return curTime.QuadPart; +} + + + +void TimeHelpers::SleepMs(int const ms) +{ + ::Sleep(ms); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/XmlTestReporter.cpp b/avango-unittest/src/avango/UnitTest++/XmlTestReporter.cpp new file mode 100644 index 00000000..1efb88d4 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/XmlTestReporter.cpp @@ -0,0 +1,126 @@ +#include + +#include +#include +#include + +using std::string; +using std::ostringstream; +using std::ostream; + +namespace { + +void ReplaceChar(string& str, char const c, string const& replacement) +{ + for (size_t pos = str.find(c); pos != string::npos; pos = str.find(c, pos + 1)) + str.replace(pos, 1, replacement); +} + +string XmlEscape(string const& value) +{ + string escaped = value; + + ReplaceChar(escaped, '&', "&"); + ReplaceChar(escaped, '<', "<"); + ReplaceChar(escaped, '>', ">"); + ReplaceChar(escaped, '\'', "'"); + ReplaceChar(escaped, '\"', """); + + return escaped; +} + +string BuildFailureMessage(string const& file, int const line, string const& message) +{ + ostringstream failureMessage; + failureMessage << file << "(" << line << ") : " << message; + return failureMessage.str(); +} + +} + +namespace UnitTest { + +XmlTestReporter::XmlTestReporter(ostream& ostream) + : m_ostream(ostream) +{ +} + +void XmlTestReporter::ReportSummary(int const totalTestCount, int const failedTestCount, + int const failureCount, float const secondsElapsed) +{ + AddXmlElement(m_ostream, NULL); + + BeginResults(m_ostream, totalTestCount, failedTestCount, failureCount, secondsElapsed); + + DeferredTestResultList const& results = GetResults(); + for (DeferredTestResultList::const_iterator i = results.begin(); i != results.end(); ++i) + { + BeginTest(m_ostream, *i); + + if (i->failed) + AddFailure(m_ostream, *i); + + EndTest(m_ostream, *i); + } + + EndResults(m_ostream); +} + +void XmlTestReporter::AddXmlElement(ostream& os, char const* encoding) +{ + os << ""; +} + +void XmlTestReporter::BeginResults(std::ostream& os, int const totalTestCount, int const failedTestCount, + int const failureCount, float const secondsElapsed) +{ + os << ""; +} + +void XmlTestReporter::EndResults(std::ostream& os) +{ + os << ""; +} + +void XmlTestReporter::BeginTest(std::ostream& os, DeferredTestResult const& result) +{ + os << ""; + else + os << "/>"; +} + +void XmlTestReporter::AddFailure(std::ostream& os, DeferredTestResult const& result) +{ + os << ">"; // close element + + for (DeferredTestResult::FailureVec::const_iterator it = result.failures.begin(); + it != result.failures.end(); + ++it) + { + string const escapedMessage = XmlEscape(it->second); + string const message = BuildFailureMessage(result.failureFile, it->first, escapedMessage); + + os << ""; + } +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/docs/UnitTest++.html b/avango-unittest/src/avango/UnitTest++/docs/UnitTest++.html new file mode 100644 index 00000000..cd404006 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/docs/UnitTest++.html @@ -0,0 +1,260 @@ + + + UnitTest++ in brief + + +

UnitTest++ in brief

+

Introduction

+

This little document serves as bare-bones documentation for UnitTest++.

+ +

For background, goals and license details, see:

+ + + +

The documentation, while sparse, aims to be practical, so it should give you enough info to get started using UnitTest++ as fast as possible.

+ +

Building UnitTest++

+

Building UnitTest++ will be specific to each platform and build environment, but it should be straightforward.

+ +

Building with Visual Studio

+

If you are using Visual Studio, go for either of the provided .sln files, depending on version. There are no prefabricated solutions for versions earlier than VS.NET 2003, but we have had reports of people building UnitTest++ with at least VS.NET 2002.

+ +

Building with Make

+

The bundled makefile is written to build with g++. It also needs sed installed in the path, and to be able to use the mv and rm shell commands. The makefile should be usable on most Posix-like platforms.

+ +

Do "make all" to generate a library and test executable. A final build step runs all unit tests to make sure that the result works as expected.

+ +

Packaging

+

You'll probably want to keep the generated library in a shared space in source control, so you can reuse it for multiple test projects. A redistributable package of UnitTest++ would consist of the generated library file, and all of the header files in UnitTest++/src/ and its per-platform subfolders. The tests directory only contains the unit tests for the library, and need not be included.

+ +

Using UnitTest++

+

The source code for UnitTest++ comes with a full test suite written using UnitTest++. This is a great place to learn techniques for testing. There is one sample .cpp file: UnitTest++/src/tests/TestUnitTest++.cpp. It covers most of UnitTest++'s features in an easy-to-grasp context, so start there if you want a quick overview of typical usage.

+ +

Getting started

+

Listed below is a minimal C++ program to run a failing test through UnitTest++.

+ +
+  // test.cpp
+  #include <UnitTest++.h>
+
+  TEST(FailSpectacularly)
+  {
+    CHECK(false);
+  }
+
+  int main()
+  {
+    return UnitTest::RunAllTests();
+  }
+
+ +

UnitTest++.h is a facade header for UnitTest++, so including that should get you all features of the library. All classes and free functions are placed in namespace UnitTest, so you need to either qualify their full names (as with RunAllTests() in the example) or add a using namespace UnitTest; statement in your .cpp files. Note that any mention of UnitTest++ functions and classes in this document assume that the UnitTest namespace has been opened.

+ +

Compiling and linking this program with UnitTest++'s static library into an executable, and running it, will produce the following output (details may vary):

+ +
+  .\test.cpp(5): error: Failure in FailSpectacularly: false
+  FAILED: 1 out of 1 tests failed (1 failures).
+  Test time: 0.00 seconds.
+
+ +

UnitTest++ attempts to report every failure in an IDE-friendly format, depending on platform (e.g. you can double-click it in Visual Studio's error list.) The exit code will be the number of failed tests, so that a failed test run always returns a non-zero exit code.

+ +

Test macros

+

To add a test, simply put the following code in a .cpp file of your choice:

+ +
+  TEST(YourTestName)
+  {
+  }
+
+ +

The TEST macro contains enough machinery to turn this slightly odd-looking syntax into legal C++, and automatically register the test in a global list. This test list forms the basis of what is executed by RunAllTests().

+ +

If you want to re-use a set of test data for more than one test, or provide setup/teardown for tests, you can use the TEST_FIXTURE macro instead. The macro requires that you pass it a class name that it will instantiate, so any setup and teardown code should be in its constructor and destructor.

+ +
+  struct SomeFixture
+  {
+    SomeFixture() { /* some setup */ }
+    ~SomeFixture() { /* some teardown */ }
+
+    int testData;
+  };
+ 
+  TEST_FIXTURE(SomeFixture, YourTestName)
+  {
+    int temp = testData;
+  }
+
+ +

Note how members of the fixture are used as if they are a part of the test, since the macro-generated test class derives from the provided fixture class.

+ +

Suite macros

+

Tests can be grouped into suites, using the SUITE macro. A suite serves as a namespace for test names, so that the same test name can be used in two difference contexts.

+ +
+  SUITE(YourSuiteName)
+  {
+    TEST(YourTestName)
+    {
+    }
+
+    TEST(YourOtherTestName)
+    {
+    }
+  }
+
+ +

This will place the tests into a C++ namespace called YourSuiteName, and make the suite name available to UnitTest++. RunAllTests() can be called for a specific suite name, so you can use this to build named groups of tests to be run together.

+ +

Simple check macros

+

In test cases, we want to check the results of our system under test. UnitTest++ provides a number of check macros that handle comparison and proper failure reporting.

+ +

The most basic variety is the boolean CHECK macro:

+ +
+  CHECK(false); // fails
+
+ +

It will fail if the boolean expression evaluates to false.

+ +

For equality checks, it's generally better to use CHECK_EQUAL:

+ +
+  CHECK_EQUAL(10, 20); // fails
+  CHECK_EQUAL("foo", "bar"); // fails
+
+ +

Note how CHECK_EQUAL is overloaded for C strings, so you don't have to resort to strcmp or similar. There is no facility for case-insensitive comparison or string searches, so you may have to drop down to a plain boolean CHECK with help from the CRT:

+ +
+  CHECK(std::strstr("zaza", "az") != 0); // succeeds
+
+ +

For floating-point comparison, equality isn't necessarily well-defined, so you should prefer the CHECK_CLOSE macro:

+ +
+  CHECK_CLOSE(3.14, 3.1415, 0.01); // succeeds
+
+ +

All of the macros are tailored to avoid unintended side-effects, for example:

+ +
+  TEST(CheckMacrosHaveNoSideEffects)
+  {
+    int i = 4;
+    CHECK_EQUAL(5, ++i); // succeeds
+    CHECK_EQUAL(5, i); // succeeds
+  }
+
+ +

The check macros guarantee that the ++i expression isn't repeated internally, as demonstrated above.

+ +

Array check macros

+

There is a set of check macros for array comparison as well:

+ +
+  const float oned[2] = { 10, 20 };
+  CHECK_ARRAY_EQUAL(oned, oned, 2); // succeeds
+  CHECK_ARRAY_CLOSE(oned, oned, 2, 0.00); // succeeds
+
+  const float twod[2][3] = { {0, 1, 2}, {2, 3, 4} };
+  CHECK_ARRAY2D_CLOSE(twod, twod, 2, 3, 0.00); // succeeds
+
+ +

The array equal macro compares elements using operator==, so CHECK_ARRAY_EQUAL won't work for an array of C strings, for example.

+ +

The array close macros are similar to the regular CHECK_CLOSE macro, and are really only useful for scalar types, that can be compared in terms of a difference between two array elements.

+ +

Note that the one-dimensional array macros work for std::vector as well, as it can be indexed just as a C array.

+ +

Exception check macros

+

Finally, there's a CHECK_THROW macro, which asserts that its enclosed expression throws the specified type:

+ +
+  struct TestException {};
+  CHECK_THROW(throw TestException(), TestException); // succeeds
+
+ +

UnitTest++ natively catches exceptions if your test code doesn't. So if your code under test throws any exception UnitTest++ will fail the test and report either using the what() method for std::exception derivatives or just a plain message for unknown exception types.

+ +

Should your test or code raise an irrecoverable error (an Access Violation on Win32, for example, or a signal on Linux), UnitTest++ will attempt to map them to an exception and fail the test, just as for other unhandled exceptions.

+ +

Time constraints

+

UnitTest++ can fail a test if it takes too long to complete, using so-called time constraints.

+ +

They come in two flavors; local and global time constraints.

+ +

Local time constraints are limited to the current scope, like so:

+ +
+  TEST(YourTimedTest)
+  {
+     // Lengthy setup...
+
+     {
+        UNITTEST_TIME_CONSTRAINT(50);
+
+        // Do time-critical stuff
+     }
+
+     // Lengthy teardown...
+  }
+
+ +

The test will fail if the "Do time-critical stuff" block takes longer than 50 ms to complete. The time-consuming setup and teardown are not measured, since the time constraint is scope-bound. It's perfectly valid to have multiple local time constraints in the same test, as long as there is only one per block.

+ +

A global time constraint, on the other hand, requires that all of the tests in a test run are faster than a specified amount of time. This allows you, when you run a suite of tests, to ask UnitTest++ to fail it entirely if any test exceeds the global constraint. The max time is passed as a parameter to an overload of RunAllTests().

+ +

If you want to use a global time constraint, but have one test that is notoriously slow, you can exempt it from inspection by using the UNITTEST_TIME_CONSTRAINT_EXEMPT macro anywhere inside the test body.

+ +
+  TEST(NotoriouslySlowTest)
+  {
+     UNITTEST_TIME_CONSTRAINT_EXEMPT();
+
+     // Oh boy, this is going to take a while
+     ...
+  }
+
+ +

Test runners

+

The RunAllTests() function has an overload that lets you customize the behavior of the runner, such as global time constraints, custom reporters, which suite to run, etc.

+ +
+  int RunAllTests(TestReporter& reporter, TestList const& list, char const* suiteName, int const maxTestTimeInMs);
+
+ +

If you attempt to pass custom parameters to RunAllTests(), note that the list parameter should have the value Test::GetTestList().

+ +

The parameterless RunAllTests() is a simple wrapper for this one, with sensible defaults.

+ +

Example setup

+

How to create a new test project varies depending on your environment, but here are some directions on common file structure and usage.

+ +

The general idea is that you keep one Main.cpp file with the entry-point which calls RunAllTests().

+ +

Then you can simply compile and link new .cpp files at will, typically one per test suite.

+ +
+   + ShaverTests/
+   |
+   +- Main.cpp
+   |
+   +- TestBrush.cpp   
+   +- TestEngine.cpp
+   +- TestRazor.cpp   
+
+ +

Each of the Test*.cpp files will contain one or more TEST macro incantations with the associated test code. There are no source-level dependencies between Main.cpp and Test*.cpp, as the TEST macro handles the registration and setup necessary for RunAllTests() to find all tests compiled into the same final executable.

+ +

UnitTest++ does not require this structure, even if this is how the library itself does it. As long as your test project contains one or more TESTs and calls RunAllTests() at one point or another, it will be handled by UnitTest++.

+ +

It's common to make the generated executable start as a post-build step, so that merely building your test project will run the tests as well. Since the exit code is the count of failures, a failed test will generally break the build, as most build engines will fail a build if any step returns a non-zero exit code.

+ + + \ No newline at end of file diff --git a/avango-unittest/src/avango/UnitTest++/tests/Main.cpp b/avango-unittest/src/avango/UnitTest++/tests/Main.cpp new file mode 100644 index 00000000..94e75eb3 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/Main.cpp @@ -0,0 +1,8 @@ +#include +#include + + +int main(int, char const *[]) +{ + return UnitTest::RunAllTests(); +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/RecordingReporter.h b/avango-unittest/src/avango/UnitTest++/tests/RecordingReporter.h new file mode 100644 index 00000000..98fa35a3 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/RecordingReporter.h @@ -0,0 +1,92 @@ +#ifndef UNITTEST_RECORDINGREPORTER_H +#define UNITTEST_RECORDINGREPORTER_H + +#include +#include + +#include + +struct RecordingReporter : public UnitTest::TestReporter +{ +private: + enum { kMaxStringLength = 256 }; + +public: + RecordingReporter() + : testRunCount(0) + , testFailedCount(0) + , lastFailedLine(0) + , testFinishedCount(0) + , lastFinishedTestTime(0) + , summaryTotalTestCount(0) + , summaryFailedTestCount(0) + , summaryFailureCount(0) + , summarySecondsElapsed(0) + { + lastStartedSuite[0] = '\0'; + lastStartedTest[0] = '\0'; + lastFailedFile[0] = '\0'; + lastFailedSuite[0] = '\0'; + lastFailedTest[0] = '\0'; + lastFailedMessage[0] = '\0'; + lastFinishedSuite[0] = '\0'; + lastFinishedTest[0] = '\0'; + } + + virtual void ReportTestStart(UnitTest::TestDetails const& test) + { + ++testRunCount; + std::strcpy(lastStartedSuite, test.suiteName); + std::strcpy(lastStartedTest, test.testName); + } + + virtual void ReportFailure(UnitTest::TestDetails const& test, char const* failure) + { + ++testFailedCount; + std::strcpy(lastFailedFile, test.filename); + lastFailedLine = test.lineNumber; + std::strcpy(lastFailedSuite, test.suiteName); + std::strcpy(lastFailedTest, test.testName); + std::strcpy(lastFailedMessage, failure); + } + + virtual void ReportTestFinish(UnitTest::TestDetails const& test, float testDuration) + { + ++testFinishedCount; + std::strcpy(lastFinishedSuite, test.suiteName); + std::strcpy(lastFinishedTest, test.testName); + lastFinishedTestTime = testDuration; + } + + virtual void ReportSummary(int totalTestCount, int failedTestCount, int failureCount, float secondsElapsed) + { + summaryTotalTestCount = totalTestCount; + summaryFailedTestCount = failedTestCount; + summaryFailureCount = failureCount; + summarySecondsElapsed = secondsElapsed; + } + + int testRunCount; + char lastStartedSuite[kMaxStringLength]; + char lastStartedTest[kMaxStringLength]; + + int testFailedCount; + char lastFailedFile[kMaxStringLength]; + int lastFailedLine; + char lastFailedSuite[kMaxStringLength]; + char lastFailedTest[kMaxStringLength]; + char lastFailedMessage[kMaxStringLength]; + + int testFinishedCount; + char lastFinishedSuite[kMaxStringLength]; + char lastFinishedTest[kMaxStringLength]; + float lastFinishedTestTime; + + int summaryTotalTestCount; + int summaryFailedTestCount; + int summaryFailureCount; + float summarySecondsElapsed; +}; + + +#endif diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestAssertHandler.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestAssertHandler.cpp new file mode 100644 index 00000000..4471455b --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestAssertHandler.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +using namespace UnitTest; + +namespace { + +TEST(ReportAssertThrowsAssertException) +{ + bool caught = false; + + try + { + ReportAssert("", "", 0); + } + catch(AssertException const&) + { + caught = true; + } + + CHECK (true == caught); +} + +TEST(ReportAssertSetsCorrectInfoInException) +{ + const int lineNumber = 12345; + const char* description = "description"; + const char* filename = "filename"; + + try + { + ReportAssert(description, filename, lineNumber); + } + catch(AssertException const& e) + { + CHECK_EQUAL(description, e.what()); + CHECK_EQUAL(filename, e.Filename()); + CHECK_EQUAL(lineNumber, e.LineNumber()); + } +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestCheckMacros.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestCheckMacros.cpp new file mode 100644 index 00000000..200601d8 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestCheckMacros.cpp @@ -0,0 +1,710 @@ +#include +#include "RecordingReporter.h" + + +namespace { + +TEST(CheckSucceedsOnTrue) +{ + bool failure = true; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK (true); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (!failure); +} + +TEST(CheckFailsOnFalse) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK (false); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(FailureReportsCorrectTestName) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + CHECK (false); + } + + CHECK_EQUAL (m_details.testName, reporter.lastFailedTest); +} + +TEST(CheckFailureIncludesCheckContents) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + const bool yaddayadda = false; + CHECK (yaddayadda); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "yaddayadda")); +} + +int ThrowingFunction() +{ + throw "Doh"; +} + +TEST(CheckFailsOnException) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK (ThrowingFunction() == 1); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckFailureBecauseOfExceptionIncludesCheckContents) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + CHECK (ThrowingFunction() == 1); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "ThrowingFunction() == 1")); +} + +TEST(CheckEqualSucceedsOnEqual) +{ + bool failure = true; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK_EQUAL (1, 1); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (!failure); +} + +TEST(CheckEqualFailsOnNotEqual) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK_EQUAL (1, 2); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckEqualFailsOnException) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK_EQUAL (ThrowingFunction(), 1); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckEqualFailureContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails const m_details("testName", "suiteName", "filename", -1); + CHECK_EQUAL (1, 123); line = __LINE__; + } + + CHECK_EQUAL("testName", reporter.lastFailedTest); + CHECK_EQUAL("suiteName", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckEqualFailureBecauseOfExceptionContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails const m_details("testName", "suiteName", "filename", -1); + CHECK_EQUAL (ThrowingFunction(), 123); line = __LINE__; + } + + CHECK_EQUAL("testName", reporter.lastFailedTest); + CHECK_EQUAL("suiteName", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckEqualFailureBecauseOfExceptionIncludesCheckContents) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + CHECK_EQUAL (ThrowingFunction(), 123); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "ThrowingFunction()")); + CHECK (std::strstr(reporter.lastFailedMessage, "123")); +} + +int g_sideEffect = 0; +int FunctionWithSideEffects() +{ + ++g_sideEffect; + return 1; +} + +TEST(CheckEqualDoesNotHaveSideEffectsWhenPassing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + CHECK_EQUAL (1, FunctionWithSideEffects()); + } + CHECK_EQUAL (1, g_sideEffect); +} + +TEST(CheckEqualDoesNotHaveSideEffectsWhenFailing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + CHECK_EQUAL (2, FunctionWithSideEffects()); + } + CHECK_EQUAL (1, g_sideEffect); +} + + +TEST(CheckCloseSucceedsOnEqual) +{ + bool failure = true; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK_CLOSE (1.0f, 1.001f, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (!failure); +} + +TEST(CheckCloseFailsOnNotEqual) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK_CLOSE (1.0f, 1.1f, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckCloseFailsOnException) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + CHECK_CLOSE ((float)ThrowingFunction(), 1.0001f, 0.1f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckCloseFailureContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails m_details("test", "suite", "filename", -1); + CHECK_CLOSE (1.0f, 1.1f, 0.01f); line = __LINE__; + } + + CHECK_EQUAL("test", reporter.lastFailedTest); + CHECK_EQUAL("suite", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckCloseFailureBecauseOfExceptionContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails m_details("closeTest", "closeSuite", "filename", -1); + CHECK_CLOSE ((float)ThrowingFunction(), 1.0001f, 0.1f); line = __LINE__; + } + + CHECK_EQUAL("closeTest", reporter.lastFailedTest); + CHECK_EQUAL("closeSuite", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckCloseFailureBecauseOfExceptionIncludesCheckContents) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + CHECK_CLOSE ((float)ThrowingFunction(), 1.0001f, 0.1f); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "(float)ThrowingFunction()")); + CHECK (std::strstr(reporter.lastFailedMessage, "1.0001f")); +} + +TEST(CheckCloseDoesNotHaveSideEffectsWhenPassing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + CHECK_CLOSE (1, FunctionWithSideEffects(), 0.1f); + } + CHECK_EQUAL (1, g_sideEffect); +} + +TEST(CheckCloseDoesNotHaveSideEffectsWhenFailing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + CHECK_CLOSE (2, FunctionWithSideEffects(), 0.1f); + } + CHECK_EQUAL (1, g_sideEffect); +} + + +class ThrowingObject +{ +public: + float operator[](int) const + { + throw "Test throw"; + } +}; + + +TEST(CheckArrayCloseSucceedsOnEqual) +{ + bool failure = true; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + const float data[4] = { 0, 1, 2, 3 }; + CHECK_ARRAY_CLOSE (data, data, 4, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (!failure); +} + +TEST(CheckArrayCloseFailsOnNotEqual) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckArrayCloseFailureIncludesCheckExpectedAndActual) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); + CHECK (std::strstr(reporter.lastFailedMessage, "was [ 0 1 3 3 ]")); +} + +TEST(CheckArrayCloseFailureContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails m_details("arrayCloseTest", "arrayCloseSuite", "filename", -1); + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); line = __LINE__; + } + + CHECK_EQUAL("arrayCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("arrayCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckArrayCloseFailureBecauseOfExceptionContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails m_details("arrayCloseTest", "arrayCloseSuite", "filename", -1); + int const data[4] = { 0, 1, 2, 3 }; + CHECK_ARRAY_CLOSE (data, ThrowingObject(), 4, 0.01f); line = __LINE__; + } + + CHECK_EQUAL("arrayCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("arrayCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckArrayCloseFailureIncludesTolerance) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + float const data1[4] = { 0, 1, 2, 3 }; + float const data2[4] = { 0, 1, 3, 3 }; + CHECK_ARRAY_CLOSE (data1, data2, 4, 0.01f); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "0.01")); +} + + +TEST(CheckArrayCloseFailsOnException) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + const float data[4] = { 0, 1, 2, 3 }; + ThrowingObject obj; + CHECK_ARRAY_CLOSE (data, obj, 3, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckArrayCloseFailureOnExceptionIncludesCheckContents) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + const float data[4] = { 0, 1, 2, 3 }; + ThrowingObject obj; + CHECK_ARRAY_CLOSE (data, obj, 3, 0.01f); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "data")); + CHECK (std::strstr(reporter.lastFailedMessage, "obj")); +} + + +TEST(CheckArrayEqualSuceedsOnEqual) +{ + bool failure = true; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + const float data[4] = { 0, 1, 2, 3 }; + CHECK_ARRAY_EQUAL (data, data, 4); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (!failure); +} + +TEST(CheckArrayEqualFailsOnNotEqual) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + CHECK_ARRAY_EQUAL (data1, data2, 4); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckArrayEqualFailureIncludesCheckExpectedAndActual) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + CHECK_ARRAY_EQUAL (data1, data2, 4); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "xpected [ 0 1 2 3 ]")); + CHECK (std::strstr(reporter.lastFailedMessage, "was [ 0 1 3 3 ]")); +} + +TEST(CheckArrayEqualFailureContainsCorrectInfo) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + int const data1[4] = { 0, 1, 2, 3 }; + int const data2[4] = { 0, 1, 3, 3 }; + CHECK_ARRAY_EQUAL (data1, data2, 4); line = __LINE__; + } + + CHECK_EQUAL ("CheckArrayEqualFailureContainsCorrectInfo", reporter.lastFailedTest); + CHECK_EQUAL (__FILE__, reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckArrayEqualFailsOnException) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + const float data[4] = { 0, 1, 2, 3 }; + ThrowingObject obj; + CHECK_ARRAY_EQUAL (data, obj, 3); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckArrayEqualFailureOnExceptionIncludesCheckContents) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + const float data[4] = { 0, 1, 2, 3 }; + ThrowingObject obj; + CHECK_ARRAY_EQUAL (data, obj, 3); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "data")); + CHECK (std::strstr(reporter.lastFailedMessage, "obj")); +} + +float const* FunctionWithSideEffects2() +{ + ++g_sideEffect; + static float const data[] = {1,2,3,4}; + return data; +} + +TEST(CheckArrayCloseDoesNotHaveSideEffectsWhenPassing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + const float data[] = { 0, 1, 2, 3 }; + CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + } + CHECK_EQUAL (1, g_sideEffect); +} + +TEST(CheckArrayCloseDoesNotHaveSideEffectsWhenFailing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + const float data[] = { 0, 1, 3, 3 }; + CHECK_ARRAY_CLOSE (data, FunctionWithSideEffects2(), 4, 0.01f); + } + CHECK_EQUAL (1, g_sideEffect); +} + +class ThrowingObject2D +{ +public: + float* operator[](int) const + { + throw "Test throw"; + } +}; + + +TEST(CheckArray2DCloseSucceedsOnEqual) +{ + bool failure = true; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + const float data[2][2] = { {0, 1}, {2, 3} }; + CHECK_ARRAY2D_CLOSE (data, data, 2, 2, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (!failure); +} + +TEST(CheckArray2DCloseFailsOnNotEqual) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + int const data1[2][2] = { {0, 1}, {2, 3} }; + int const data2[2][2] = { {0, 1}, {3, 3} }; + CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckArray2DCloseFailureIncludesCheckExpectedAndActual) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + int const data1[2][2] = { {0, 1}, {2, 3} }; + int const data2[2][2] = { {0, 1}, {3, 3} }; + CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "xpected [ [ 0 1 ] [ 2 3 ] ]")); + CHECK (std::strstr(reporter.lastFailedMessage, "was [ [ 0 1 ] [ 3 3 ] ]")); +} + +TEST(CheckArray2DCloseFailureContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails m_details("array2DCloseTest", "array2DCloseSuite", "filename", -1); + int const data1[2][2] = { {0, 1}, {2, 3} }; + int const data2[2][2] = { {0, 1}, {3, 3} }; + CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); line = __LINE__; + } + + CHECK_EQUAL("array2DCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("array2DCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckArray2DCloseFailureBecauseOfExceptionContainsCorrectDetails) +{ + int line = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UnitTest::TestDetails m_details("array2DCloseTest", "array2DCloseSuite", "filename", -1); + const float data[2][2] = { {0, 1}, {2, 3} }; + CHECK_ARRAY2D_CLOSE (data, ThrowingObject2D(), 2, 2, 0.01f); line = __LINE__; + } + + CHECK_EQUAL("array2DCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("array2DCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (line, reporter.lastFailedLine); +} + +TEST(CheckArray2DCloseFailureIncludesTolerance) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + float const data1[2][2] = { {0, 1}, {2, 3} }; + float const data2[2][2] = { {0, 1}, {3, 3} }; + CHECK_ARRAY2D_CLOSE (data1, data2, 2, 2, 0.01f); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "0.01")); +} + +TEST(CheckArray2DCloseFailsOnException) +{ + bool failure = false; + { + RecordingReporter reporter; + UnitTest::TestResults testResults_(&reporter); + const float data[2][2] = { {0, 1}, {2, 3} }; + ThrowingObject2D obj; + CHECK_ARRAY2D_CLOSE (data, obj, 2, 2, 0.01f); + failure = (testResults_.GetFailureCount() > 0); + } + + CHECK (failure); +} + +TEST(CheckArray2DCloseFailureOnExceptionIncludesCheckContents) +{ + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + const float data[2][2] = { {0, 1}, {2, 3} }; + ThrowingObject2D obj; + CHECK_ARRAY2D_CLOSE (data, obj, 2, 2, 0.01f); + } + + CHECK (std::strstr(reporter.lastFailedMessage, "data")); + CHECK (std::strstr(reporter.lastFailedMessage, "obj")); +} + +float const* const* FunctionWithSideEffects3() +{ + ++g_sideEffect; + static float const data1[] = {0,1}; + static float const data2[] = {2,3}; + static const float* const data[] = {data1, data2}; + return data; +} + +TEST(CheckArray2DCloseDoesNotHaveSideEffectsWhenPassing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + const float data[2][2] = { {0, 1}, {2, 3} }; + CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + } + CHECK_EQUAL (1, g_sideEffect); +} + +TEST(CheckArray2DCloseDoesNotHaveSideEffectsWhenFailing) +{ + g_sideEffect = 0; + { + UnitTest::TestResults testResults_; + const float data[2][2] = { {0, 1}, {3, 3} }; + CHECK_ARRAY2D_CLOSE (data, FunctionWithSideEffects3(), 2, 2, 0.01f); + } + CHECK_EQUAL (1, g_sideEffect); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestChecks.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestChecks.cpp new file mode 100644 index 00000000..250136d5 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestChecks.cpp @@ -0,0 +1,290 @@ +#include +#include "RecordingReporter.h" + +using namespace UnitTest; + + +namespace { + + +TEST(CheckEqualWithUnsignedLong) +{ + TestResults results; + unsigned long something = 2; + CHECK_EQUAL( something, something ); +} + +TEST(CheckEqualsWithStringsFailsOnDifferentStrings) +{ + char txt1[] = "Hello"; + char txt2[] = "Hallo"; + TestResults results; + CheckEqual(results, txt1, txt2, TestDetails("", "", "", 0)); + CHECK_EQUAL (1, results.GetFailureCount()); +} + +char txt1[] = "Hello"; // non-const on purpose so no folding of duplicate data +char txt2[] = "Hello"; + +TEST(CheckEqualsWithStringsWorksOnContentsNonConstNonConst) +{ + char const* const p1 = txt1; + char const* const p2 = txt2; + TestResults results; + CheckEqual(results, p1, p2, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckEqualsWithStringsWorksOnContentsConstConst) +{ + char* const p1 = txt1; + char* const p2 = txt2; + TestResults results; + CheckEqual(results, p1, p2, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckEqualsWithStringsWorksOnContentsNonConstConst) +{ + char* const p1 = txt1; + char const* const p2 = txt2; + TestResults results; + CheckEqual(results, p1, p2, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckEqualsWithStringsWorksOnContentsConstNonConst) +{ + char const* const p1 = txt1; + char* const p2 = txt2; + TestResults results; + CheckEqual(results, p1, p2, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckEqualsWithStringsWorksOnContentsWithALiteral) +{ + char const* const p1 = txt1; + TestResults results; + CheckEqual(results, "Hello", p1, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckEqualFailureIncludesCheckExpectedAndActual) +{ + RecordingReporter reporter; + TestResults results(&reporter); + const int something = 2; + CheckEqual (results, 1, something, TestDetails("", "", "", 0)); + + CHECK (std::strstr(reporter.lastFailedMessage, "xpected 1")); + CHECK (std::strstr(reporter.lastFailedMessage, "was 2")); +} + +TEST(CheckEqualFailureIncludesDetails) +{ + RecordingReporter reporter; + TestResults results(&reporter); + TestDetails const details("mytest", "mysuite", "file.h", 101); + + CheckEqual (results, 1, 2, details); + + CHECK_EQUAL("mytest", reporter.lastFailedTest); + CHECK_EQUAL("mysuite", reporter.lastFailedSuite); + CHECK_EQUAL("file.h", reporter.lastFailedFile); + CHECK_EQUAL(101, reporter.lastFailedLine); +} + +TEST(CheckCloseTrue) +{ + TestResults results; + CheckClose(results, 3.001f, 3.0f, 0.1f, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckCloseFalse) +{ + TestResults results; + CheckClose(results, 3.12f, 3.0f, 0.1f, TestDetails("", "", "", 0)); + CHECK_EQUAL (1, results.GetFailureCount()); +} + +TEST(CheckCloseWithZeroEpsilonWorksForSameNumber) +{ + TestResults results; + CheckClose(results, 0.1f, 0.1f, 0, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckCloseWithNaNFails) +{ + union + { + unsigned int bitpattern; + float nan; + }; + bitpattern = 0xFFFFFFFF; + TestResults results; + CheckClose(results, 3.0f, nan, 0.1f, TestDetails("", "", "", 0)); + CHECK_EQUAL (1, results.GetFailureCount()); +} + +TEST(CheckCloseWithNaNAgainstItselfFails) +{ + union + { + unsigned int bitpattern; + float nan; + }; + bitpattern = 0xFFFFFFFF; + TestResults results; + CheckClose(results, nan, nan, 0.1f, TestDetails("", "", "", 0)); + CHECK_EQUAL (1, results.GetFailureCount()); +} + +TEST(CheckCloseFailureIncludesCheckExpectedAndActual) +{ + RecordingReporter reporter; + TestResults results(&reporter); + const float expected = 0.9f; + const float actual = 1.1f; + CheckClose (results, expected, actual, 0.01f, TestDetails("", "", "", 0)); + + CHECK (std::strstr(reporter.lastFailedMessage, "xpected 0.9")); + CHECK (std::strstr(reporter.lastFailedMessage, "was 1.1")); +} + +TEST(CheckCloseFailureIncludesTolerance) +{ + RecordingReporter reporter; + TestResults results(&reporter); + CheckClose (results, 2, 3, 0.01f, TestDetails("", "", "", 0)); + + CHECK (std::strstr(reporter.lastFailedMessage, "0.01")); +} + +TEST(CheckCloseFailureIncludesDetails) +{ + RecordingReporter reporter; + TestResults results(&reporter); + TestDetails const details("mytest", "mysuite", "header.h", 10); + + CheckClose (results, 2, 3, 0.01f, details); + + CHECK_EQUAL("mytest", reporter.lastFailedTest); + CHECK_EQUAL("mysuite", reporter.lastFailedSuite); + CHECK_EQUAL("header.h", reporter.lastFailedFile); + CHECK_EQUAL(10, reporter.lastFailedLine); +} + + +TEST(CheckArrayEqualTrue) +{ + TestResults results; + + int const array[3] = { 1, 2, 3 }; + CheckArrayEqual(results, array, array, 3, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckArrayEqualFalse) +{ + TestResults results; + + int const array1[3] = { 1, 2, 3 }; + int const array2[3] = { 1, 2, 2 }; + CheckArrayEqual(results, array1, array2, 3, TestDetails("", "", "", 0)); + CHECK_EQUAL (1, results.GetFailureCount()); +} + +TEST(CheckArrayCloseTrue) +{ + TestResults results; + + float const array1[3] = { 1.0f, 1.5f, 2.0f }; + float const array2[3] = { 1.01f, 1.51f, 2.01f }; + CheckArrayClose(results, array1, array2, 3, 0.02f, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckArrayCloseFalse) +{ + TestResults results; + + float const array1[3] = { 1.0f, 1.5f, 2.0f }; + float const array2[3] = { 1.01f, 1.51f, 2.01f }; + CheckArrayClose(results, array1, array2, 3, 0.001f, TestDetails("", "", "", 0)); + CHECK_EQUAL (1, results.GetFailureCount()); +} + +TEST(CheckArrayCloseFailureIncludesDetails) +{ + RecordingReporter reporter; + TestResults results(&reporter); + TestDetails const details("arrayCloseTest", "arrayCloseSuite", "file", 1337); + + float const array1[3] = { 1.0f, 1.5f, 2.0f }; + float const array2[3] = { 1.01f, 1.51f, 2.01f }; + CheckArrayClose(results, array1, array2, 3, 0.001f, details); + + CHECK_EQUAL("arrayCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("arrayCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL("file", reporter.lastFailedFile); + CHECK_EQUAL(1337, reporter.lastFailedLine); +} + + +TEST(CheckArray2DCloseTrue) +{ + TestResults results; + + float const array1[3][3] = { { 1.0f, 1.5f, 2.0f }, + { 2.0f, 2.5f, 3.0f }, + { 3.0f, 3.5f, 4.0f } }; + float const array2[3][3] = { { 1.01f, 1.51f, 2.01f }, + { 2.01f, 2.51f, 3.01f }, + { 3.01f, 3.51f, 4.01f } }; + CheckArray2DClose(results, array1, array2, 3, 3, 0.02f, TestDetails("", "", "", 0)); + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(CheckArray2DCloseFalse) +{ + TestResults results; + + float const array1[3][3] = { { 1.0f, 1.5f, 2.0f }, + { 2.0f, 2.5f, 3.0f }, + { 3.0f, 3.5f, 4.0f } }; + float const array2[3][3] = { { 1.01f, 1.51f, 2.01f }, + { 2.01f, 2.51f, 3.01f }, + { 3.01f, 3.51f, 4.01f } }; + CheckArray2DClose(results, array1, array2, 3, 3, 0.001f, TestDetails("", "", "", 0)); + CHECK_EQUAL (1, results.GetFailureCount()); +} + +TEST(CheckCloseWithDoublesSucceeds) +{ + CHECK_CLOSE(0.5, 0.5, 0.0001); +} + +TEST(CheckArray2DCloseFailureIncludesDetails) +{ + RecordingReporter reporter; + TestResults results(&reporter); + TestDetails const details("array2DCloseTest", "array2DCloseSuite", "file", 1234); + + float const array1[3][3] = { { 1.0f, 1.5f, 2.0f }, + { 2.0f, 2.5f, 3.0f }, + { 3.0f, 3.5f, 4.0f } }; + float const array2[3][3] = { { 1.01f, 1.51f, 2.01f }, + { 2.01f, 2.51f, 3.01f }, + { 3.01f, 3.51f, 4.01f } }; + CheckArray2DClose(results, array1, array2, 3, 3, 0.001f, details); + + CHECK_EQUAL("array2DCloseTest", reporter.lastFailedTest); + CHECK_EQUAL("array2DCloseSuite", reporter.lastFailedSuite); + CHECK_EQUAL("file", reporter.lastFailedFile); + CHECK_EQUAL(1234, reporter.lastFailedLine); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestDeferredTestReporter.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestDeferredTestReporter.cpp new file mode 100644 index 00000000..26afdd98 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestDeferredTestReporter.cpp @@ -0,0 +1,104 @@ +#include +#include + +#include + +namespace UnitTest +{ + +struct MockDeferredTestReporter : public DeferredTestReporter +{ + virtual void ReportSummary(int, int, int, float) + { + } +}; + +struct DeferredTestReporterFixture +{ + DeferredTestReporterFixture() + : testName("UniqueTestName") + , testSuite("UniqueTestSuite") + , fileName("filename.h") + , lineNumber(12) + , details(testName.c_str(), testSuite.c_str(), fileName.c_str(), lineNumber) + { + } + + MockDeferredTestReporter reporter; + std::string const testName; + std::string const testSuite; + std::string const fileName; + int const lineNumber; + TestDetails const details; +}; + +TEST_FIXTURE(DeferredTestReporterFixture, ReportTestStartCreatesANewDeferredTest) +{ + reporter.ReportTestStart(details); + CHECK_EQUAL(1, (int)reporter.GetResults().size()); +} + +TEST_FIXTURE(DeferredTestReporterFixture, ReportTestStartCapturesTestNameAndSuite) +{ + reporter.ReportTestStart(details); + + DeferredTestResult const& result = reporter.GetResults().at(0); + CHECK_EQUAL(testName.c_str(), result.testName); + CHECK_EQUAL(testSuite.c_str(), result.suiteName); +} + +TEST_FIXTURE(DeferredTestReporterFixture, ReportTestEndCapturesTestTime) +{ + float const elapsed = 123.45f; + reporter.ReportTestStart(details); + reporter.ReportTestFinish(details, elapsed); + + DeferredTestResult const& result = reporter.GetResults().at(0); + CHECK_CLOSE(elapsed, result.timeElapsed, 0.0001f); +} + +TEST_FIXTURE(DeferredTestReporterFixture, ReportFailureSavesFailureDetails) +{ + char const* failure = "failure"; + + reporter.ReportTestStart(details); + reporter.ReportFailure(details, failure); + + DeferredTestResult const& result = reporter.GetResults().at(0); + CHECK(result.failed == true); + CHECK_EQUAL(fileName.c_str(), result.failureFile); +} + +TEST_FIXTURE(DeferredTestReporterFixture, ReportFailureSavesFailureDetailsForMultipleFailures) +{ + char const* failure1 = "failure 1"; + char const* failure2 = "failure 2"; + + reporter.ReportTestStart(details); + reporter.ReportFailure(details, failure1); + reporter.ReportFailure(details, failure2); + + DeferredTestResult const& result = reporter.GetResults().at(0); + CHECK_EQUAL(2u, result.failures.size()); + CHECK_EQUAL(failure1, result.failures[0].second); + CHECK_EQUAL(failure2, result.failures[1].second); +} + +TEST_FIXTURE(DeferredTestReporterFixture, DeferredTestReporterTakesCopyOfFailureMessage) +{ + reporter.ReportTestStart(details); + + char failureMessage[128]; + char const* goodStr = "Real failure message"; + char const* badStr = "Bogus failure message"; + + std::strcpy(failureMessage, goodStr); + reporter.ReportFailure(details, failureMessage); + std::strcpy(failureMessage, badStr); + + DeferredTestResult const& result = reporter.GetResults().at(0); + DeferredTestResult::Failure const& failure = result.failures.at(0); + CHECK_EQUAL(goodStr, failure.second); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestMemoryOutStream.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestMemoryOutStream.cpp new file mode 100644 index 00000000..b59131b3 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestMemoryOutStream.cpp @@ -0,0 +1,150 @@ +#include + +#include +#include + +using namespace UnitTest; + +namespace { + +TEST (DefaultIsEmptyString) +{ + MemoryOutStream const stream; + CHECK (stream.GetText() != 0); + CHECK_EQUAL ("", stream.GetText()); +} + +TEST (StreamingTextCopiesCharacters) +{ + MemoryOutStream stream; + stream << "Lalala"; + CHECK_EQUAL ("Lalala", stream.GetText()); +} + +TEST (StreamingMultipleTimesConcatenatesResult) +{ + MemoryOutStream stream; + stream << "Bork" << "Foo" << "Bar"; + CHECK_EQUAL ("BorkFooBar", stream.GetText()); +} + +TEST (StreamingIntWritesCorrectCharacters) +{ + MemoryOutStream stream; + stream << (int)123; + CHECK_EQUAL ("123", stream.GetText()); +} + +TEST (StreamingUnsignedIntWritesCorrectCharacters) +{ + MemoryOutStream stream; + stream << (unsigned int)123; + CHECK_EQUAL ("123", stream.GetText()); +} + +TEST (StreamingLongWritesCorrectCharacters) +{ + MemoryOutStream stream; + stream << (long)(-123); + CHECK_EQUAL ("-123", stream.GetText()); +} + +TEST (StreamingUnsignedLongWritesCorrectCharacters) +{ + MemoryOutStream stream; + stream << (unsigned long)123; + CHECK_EQUAL ("123", stream.GetText()); +} + +TEST (StreamingFloatWritesCorrectCharacters) +{ + MemoryOutStream stream; + stream << 3.1415f; + CHECK (std::strstr(stream.GetText(), "3.1415")); +} + +TEST (StreamingDoubleWritesCorrectCharacters) +{ + MemoryOutStream stream; + stream << 3.1415; + CHECK (std::strstr(stream.GetText(), "3.1415")); +} + +TEST (StreamingPointerWritesCorrectCharacters) +{ + MemoryOutStream stream; + int* p = (int*)0x1234; + stream << p; + CHECK (std::strstr(stream.GetText(), "1234")); +} + +TEST (StreamingSizeTWritesCorrectCharacters) +{ + MemoryOutStream stream; + size_t const s = 53124; + stream << s; + CHECK_EQUAL ("53124", stream.GetText()); +} + +#ifdef UNITTEST_USE_CUSTOM_STREAMS + +TEST (StreamInitialCapacityIsCorrect) +{ + MemoryOutStream stream(MemoryOutStream::GROW_CHUNK_SIZE); + CHECK_EQUAL ((int)MemoryOutStream::GROW_CHUNK_SIZE, stream.GetCapacity()); +} + +TEST (StreamInitialCapacityIsMultipleOfGrowChunkSize) +{ + MemoryOutStream stream(MemoryOutStream::GROW_CHUNK_SIZE + 1); + CHECK_EQUAL ((int)MemoryOutStream::GROW_CHUNK_SIZE * 2, stream.GetCapacity()); +} + + +TEST (ExceedingCapacityGrowsBuffer) +{ + MemoryOutStream stream(MemoryOutStream::GROW_CHUNK_SIZE); + stream << "012345678901234567890123456789"; + char const* const oldBuffer = stream.GetText(); + stream << "0123456789"; + CHECK (oldBuffer != stream.GetText()); +} + +TEST (ExceedingCapacityGrowsBufferByGrowChunk) +{ + MemoryOutStream stream(MemoryOutStream::GROW_CHUNK_SIZE); + stream << "0123456789012345678901234567890123456789"; + CHECK_EQUAL (MemoryOutStream::GROW_CHUNK_SIZE * 2, stream.GetCapacity()); +} + +TEST (WritingStringLongerThanCapacityFitsInNewBuffer) +{ + MemoryOutStream stream(8); + stream << "0123456789ABCDEF"; + CHECK_EQUAL ("0123456789ABCDEF", stream.GetText()); +} + +TEST (WritingIntLongerThanCapacityFitsInNewBuffer) +{ + MemoryOutStream stream(8); + stream << "aaaa" << 123456;; + CHECK_EQUAL ("aaaa123456", stream.GetText()); +} + +TEST (WritingFloatLongerThanCapacityFitsInNewBuffer) +{ + MemoryOutStream stream(8); + stream << "aaaa" << 123456.0f;; + CHECK_EQUAL ("aaaa123456.000000f", stream.GetText()); +} + +TEST (WritingSizeTLongerThanCapacityFitsInNewBuffer) +{ + MemoryOutStream stream(8); + stream << "aaaa" << size_t(32145); + CHECK_EQUAL ("aaaa32145", stream.GetText()); +} + +#endif + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTest.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTest.cpp new file mode 100644 index 00000000..d0886029 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTest.cpp @@ -0,0 +1,97 @@ +#include +#include +#include + +using namespace UnitTest; + +namespace { + +TEST (PassingTestHasNoFailures) +{ + class PassingTest : public Test + { + public: + PassingTest() : Test("passing") {} + virtual void RunImpl(TestResults& testResults_) const + { + CHECK(true); + } + }; + + TestResults results; + PassingTest().Run(results); + CHECK_EQUAL(0, results.GetFailureCount()); +} + + +TEST (FailingTestHasFailures) +{ + class FailingTest : public Test + { + public: + FailingTest() : Test("failing") {} + virtual void RunImpl(TestResults& testResults_) const + { + CHECK(false); + } + }; + + TestResults results; + FailingTest().Run(results); + CHECK_EQUAL(1, results.GetFailureCount()); +} + + +TEST (ThrowingTestsAreReportedAsFailures) +{ + class CrashingTest : public Test + { + public: + CrashingTest() : Test("throwing") {} + virtual void RunImpl(TestResults&) const + { + throw "Blah"; + } + }; + + TestResults results; + CrashingTest().Run(results); + CHECK_EQUAL(1, results.GetFailureCount()); +} + + +#ifndef UNITTEST_MINGW +TEST (CrashingTestsAreReportedAsFailures) +{ + class CrashingTest : public Test + { + public: + CrashingTest() : Test("crashing") {} + virtual void RunImpl(TestResults&) const + { + reinterpret_cast< void (*)() >(0)(); + } + }; + + TestResults results; + CrashingTest().Run(results); + CHECK_EQUAL(1, results.GetFailureCount()); +} +#endif + +TEST (TestWithUnspecifiedSuiteGetsDefaultSuite) +{ + Test test("test"); + CHECK(test.m_details.suiteName != NULL); + CHECK_EQUAL("DefaultSuite", test.m_details.suiteName); +} + +TEST (TestReflectsSpecifiedSuiteName) +{ + Test test("test", "testSuite"); + CHECK(test.m_details.suiteName != NULL); + CHECK_EQUAL("testSuite", test.m_details.suiteName); +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTestList.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTestList.cpp new file mode 100644 index 00000000..99b35bb0 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTestList.cpp @@ -0,0 +1,50 @@ +#include +#include + +using namespace UnitTest; + +namespace { + + +TEST (TestListIsEmptyByDefault) +{ + TestList list; + CHECK (list.GetHead() == 0); +} + +TEST (AddingTestSetsHeadToTest) +{ + Test test("test"); + TestList list; + list.Add(&test); + + CHECK (list.GetHead() == &test); + CHECK (test.next == 0); +} + +TEST (AddingSecondTestAddsItToEndOfList) +{ + Test test1("test1"); + Test test2("test2"); + + TestList list; + list.Add(&test1); + list.Add(&test2); + + CHECK (list.GetHead() == &test1); + CHECK (test1.next == &test2); + CHECK (test2.next == 0); +} + +TEST (ListAdderAddsTestToList) +{ + TestList list; + + Test test(""); + ListAdder adder(list, &test); + + CHECK (list.GetHead() == &test); + CHECK (test.next == 0); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTestMacros.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTestMacros.cpp new file mode 100644 index 00000000..a0864493 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTestMacros.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include "RecordingReporter.h" + +using namespace UnitTest; + +namespace { + +TestList list1; +TEST_EX(DummyTest, list1) +{ + (void)testResults_; +} + +TEST (TestsAreAddedToTheListThroughMacro) +{ + CHECK (list1.GetHead() != 0); + CHECK (list1.GetHead()->next == 0); +} + +struct ThrowingThingie +{ + ThrowingThingie() : dummy(false) + { + if (!dummy) + throw "Oops"; + } + bool dummy; +}; + +TestList list2; +TEST_FIXTURE_EX(ThrowingThingie,DummyTestName,list2) +{ + (void)testResults_; +} + +TEST (ExceptionsInFixtureAreReportedAsHappeningInTheFixture) +{ + RecordingReporter reporter; + TestResults result(&reporter); + list2.GetHead()->Run(result); + + CHECK (strstr(reporter.lastFailedMessage, "xception")); + CHECK (strstr(reporter.lastFailedMessage, "fixture")); + CHECK (strstr(reporter.lastFailedMessage, "ThrowingThingie")); +} + +struct DummyFixture +{ + int x; +}; + +// We're really testing the macros so we just want them to compile and link +SUITE(TestSuite1) +{ + + TEST(SimilarlyNamedTestsInDifferentSuitesWork) + { + (void)testResults_; + } + + TEST_FIXTURE(DummyFixture,SimilarlyNamedFixtureTestsInDifferentSuitesWork) + { + (void)testResults_; + } + +} + +SUITE(TestSuite2) +{ + + TEST(SimilarlyNamedTestsInDifferentSuitesWork) + { + (void)testResults_; + } + + TEST_FIXTURE(DummyFixture,SimilarlyNamedFixtureTestsInDifferentSuitesWork) + { + (void)testResults_; + } + +} + +TestList macroTestList1; +TEST_EX(MacroTestHelper1,macroTestList1) +{ + (void)testResults_; +} + +TEST(TestAddedWithTEST_EXMacroGetsDefaultSuite) +{ + CHECK(macroTestList1.GetHead() != NULL); + CHECK_EQUAL ("MacroTestHelper1", macroTestList1.GetHead()->m_details.testName); + CHECK_EQUAL ("DefaultSuite", macroTestList1.GetHead()->m_details.suiteName); +} + +TestList macroTestList2; +TEST_FIXTURE_EX(DummyFixture,MacroTestHelper2,macroTestList2) +{ + (void)testResults_; +} + +TEST(TestAddedWithTEST_FIXTURE_EXMacroGetsDefaultSuite) +{ + CHECK(macroTestList2.GetHead() != NULL); + CHECK_EQUAL ("MacroTestHelper2", macroTestList2.GetHead()->m_details.testName); + CHECK_EQUAL ("DefaultSuite", macroTestList2.GetHead()->m_details.suiteName); +} + +struct FixtureCtorThrows +{ + FixtureCtorThrows() { throw "exception"; } +}; + +TestList throwingFixtureTestList1; +TEST_FIXTURE_EX(FixtureCtorThrows, FixtureCtorThrowsTestName, throwingFixtureTestList1) +{ + (void)testResults_; +} + +TEST(FixturesWithThrowingCtorsAreFailures) +{ + CHECK(throwingFixtureTestList1.GetHead() != NULL); + RecordingReporter reporter; + TestResults result(&reporter); + throwingFixtureTestList1.GetHead()->Run(result); + + int const failureCount = result.GetFailedTestCount(); + CHECK_EQUAL(1, failureCount); + CHECK(strstr(reporter.lastFailedMessage, "while constructing fixture")); +} + +struct FixtureDtorThrows +{ + ~FixtureDtorThrows() { throw "exception"; } +}; + +TestList throwingFixtureTestList2; +TEST_FIXTURE_EX(FixtureDtorThrows, FixtureDtorThrowsTestName, throwingFixtureTestList2) +{ + (void)testResults_; +} + +TEST(FixturesWithThrowingDtorsAreFailures) +{ + CHECK(throwingFixtureTestList2.GetHead() != NULL); + RecordingReporter reporter; + TestResults result(&reporter); + throwingFixtureTestList2.GetHead()->Run(result); + + int const failureCount = result.GetFailedTestCount(); + CHECK_EQUAL(1, failureCount); + CHECK(strstr(reporter.lastFailedMessage, "while destroying fixture")); +} + +} + +// We're really testing if it's possible to use the same suite in two files +// to compile and link successfuly (TestTestSuite.cpp has suite with the same name) +// Note: we are outside of the anonymous namespace +SUITE(SameTestSuite) +{ + TEST(DummyTest1) + { + (void)testResults_; + } +} + diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTestResults.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTestResults.cpp new file mode 100644 index 00000000..2f7ee305 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTestResults.cpp @@ -0,0 +1,111 @@ +#include +#include +#include "RecordingReporter.h" + +using namespace UnitTest; + +namespace { + +TestDetails const details("testname", "suitename", "filename", 123); + + +TEST(StartsWithNoTestsRun) +{ + TestResults results; + CHECK_EQUAL (0, results.GetTotalTestCount()); +} + +TEST(RecordsNumbersOfTests) +{ + TestResults results; + results.OnTestStart(details); + results.OnTestStart(details); + results.OnTestStart(details); + CHECK_EQUAL(3, results.GetTotalTestCount()); +} + +TEST(StartsWithNoTestsFailing) +{ + TestResults results; + CHECK_EQUAL (0, results.GetFailureCount()); +} + +TEST(RecordsNumberOfFailures) +{ + TestResults results; + results.OnTestFailure(details, ""); + results.OnTestFailure(details, ""); + CHECK_EQUAL(2, results.GetFailureCount()); +} + +TEST(RecordsNumberOfFailedTests) +{ + TestResults results; + + results.OnTestStart(details); + results.OnTestFailure(details, ""); + results.OnTestFinish(details, 0); + + results.OnTestStart(details); + results.OnTestFailure(details, ""); + results.OnTestFailure(details, ""); + results.OnTestFailure(details, ""); + results.OnTestFinish(details, 0); + + CHECK_EQUAL (2, results.GetFailedTestCount()); +} + +TEST(NotifiesReporterOfTestStartWithCorrectInfo) +{ + RecordingReporter reporter; + TestResults results(&reporter); + results.OnTestStart(details); + + CHECK_EQUAL (1, reporter.testRunCount); + CHECK_EQUAL ("suitename", reporter.lastStartedSuite); + CHECK_EQUAL ("testname", reporter.lastStartedTest); +} + +TEST(NotifiesReporterOfTestFailureWithCorrectInfo) +{ + RecordingReporter reporter; + TestResults results(&reporter); + + results.OnTestFailure(details, "failurestring"); + CHECK_EQUAL (1, reporter.testFailedCount); + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (123, reporter.lastFailedLine); + CHECK_EQUAL ("suitename", reporter.lastFailedSuite); + CHECK_EQUAL ("testname", reporter.lastFailedTest); + CHECK_EQUAL ("failurestring", reporter.lastFailedMessage); +} + +TEST(NotifiesReporterOfCheckFailureWithCorrectInfo) +{ + RecordingReporter reporter; + TestResults results(&reporter); + + results.OnTestFailure(details, "failurestring"); + CHECK_EQUAL (1, reporter.testFailedCount); + + CHECK_EQUAL ("filename", reporter.lastFailedFile); + CHECK_EQUAL (123, reporter.lastFailedLine); + CHECK_EQUAL ("testname", reporter.lastFailedTest); + CHECK_EQUAL ("suitename", reporter.lastFailedSuite); + CHECK_EQUAL ("failurestring", reporter.lastFailedMessage); +} + +TEST(NotifiesReporterOfTestEnd) +{ + RecordingReporter reporter; + TestResults results(&reporter); + + results.OnTestFinish(details, 0.1234f); + CHECK_EQUAL (1, reporter.testFinishedCount); + CHECK_EQUAL ("testname", reporter.lastFinishedTest); + CHECK_EQUAL ("suitename", reporter.lastFinishedSuite); + CHECK_CLOSE (0.1234f, reporter.lastFinishedTestTime, 0.0001f); +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTestRunner.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTestRunner.cpp new file mode 100644 index 00000000..1605f928 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTestRunner.cpp @@ -0,0 +1,233 @@ +#include +#include "RecordingReporter.h" +#include +#include +#include +#include + +using namespace UnitTest; + +namespace +{ + +struct MockTest : public Test +{ + MockTest(char const* testName, bool const success_, bool const assert_, int const count_ = 1) + : Test(testName) + , success(success_) + , asserted(assert_) + , count(count_) + { + } + + virtual void RunImpl(TestResults& testResults_) const + { + for (int i=0; i < count; ++i) + { + if (asserted) + ReportAssert("desc", "file", 0); + else if (!success) + testResults_.OnTestFailure(m_details, "message"); + } + } + + bool const success; + bool const asserted; + int const count; +}; + + +struct TestRunnerFixture +{ + RecordingReporter reporter; + TestList list; +}; + +TEST_FIXTURE(TestRunnerFixture, TestStartIsReportedCorrectly) +{ + MockTest test("goodtest", true, false); + list.Add(&test); + + RunAllTests(reporter, list, 0); + CHECK_EQUAL(1, reporter.testRunCount); + CHECK_EQUAL("goodtest", reporter.lastStartedTest); +} + +TEST_FIXTURE(TestRunnerFixture, TestFinishIsReportedCorrectly) +{ + MockTest test("goodtest", true, false); + list.Add(&test); + + RunAllTests(reporter, list, 0); + CHECK_EQUAL(1, reporter.testFinishedCount); + CHECK_EQUAL("goodtest", reporter.lastFinishedTest); +} + +class SlowTest : public Test +{ +public: + SlowTest() : Test("slow", "somesuite", "filename", 123) {} + virtual void RunImpl(TestResults&) const + { + TimeHelpers::SleepMs(20); + } +}; + +TEST_FIXTURE(TestRunnerFixture, TestFinishIsCalledWithCorrectTime) +{ + SlowTest test; + list.Add(&test); + + RunAllTests(reporter, list, 0); + CHECK (reporter.lastFinishedTestTime >= 0.005f && reporter.lastFinishedTestTime <= 0.050f); +} + +TEST_FIXTURE(TestRunnerFixture, FailureCountIsZeroWhenNoTestsAreRun) +{ + CHECK_EQUAL(0, RunAllTests(reporter, list, 0)); + CHECK_EQUAL(0, reporter.testRunCount); + CHECK_EQUAL(0, reporter.testFailedCount); +} + +TEST_FIXTURE(TestRunnerFixture, CallsReportFailureOncePerFailingTest) +{ + MockTest test1("test", false, false); + list.Add(&test1); + MockTest test2("test", true, false); + list.Add(&test2); + MockTest test3("test", false, false); + list.Add(&test3); + + CHECK_EQUAL(2, RunAllTests(reporter, list, 0)); + CHECK_EQUAL(2, reporter.testFailedCount); +} + +TEST_FIXTURE(TestRunnerFixture, TestsThatAssertAreReportedAsFailing) +{ + MockTest test("test", true, true); + list.Add(&test); + + RunAllTests(reporter, list, 0); + CHECK_EQUAL(1, reporter.testFailedCount); +} + + +TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfTestCount) +{ + MockTest test1("test", true, false); + MockTest test2("test", true, false); + MockTest test3("test", true, false); + list.Add(&test1); + list.Add(&test2); + list.Add(&test3); + + RunAllTests(reporter, list, 0); + CHECK_EQUAL(3, reporter.summaryTotalTestCount); +} + +TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfFailedTests) +{ + MockTest test1("test", false, false, 2); + MockTest test2("test", true, false); + MockTest test3("test", false, false, 3); + list.Add(&test1); + list.Add(&test2); + list.Add(&test3); + + RunAllTests(reporter, list, 0); + CHECK_EQUAL(2, reporter.summaryFailedTestCount); +} + +TEST_FIXTURE(TestRunnerFixture, ReporterNotifiedOfFailures) +{ + MockTest test1("test", false, false, 2); + MockTest test2("test", true, false); + MockTest test3("test", false, false, 3); + list.Add(&test1); + list.Add(&test2); + list.Add(&test3); + + RunAllTests(reporter, list, 0); + CHECK_EQUAL(5, reporter.summaryFailureCount); +} + +TEST_FIXTURE(TestRunnerFixture, SlowTestPassesForHighTimeThreshold) +{ + SlowTest test; + list.Add(&test); + RunAllTests(reporter, list, 0); + CHECK_EQUAL (0, reporter.testFailedCount); +} + +TEST_FIXTURE(TestRunnerFixture, SlowTestFailsForLowTimeThreshold) +{ + SlowTest test; + list.Add(&test); + RunAllTests(reporter, list, 0, 3); + CHECK_EQUAL (1, reporter.testFailedCount); +} + +TEST_FIXTURE(TestRunnerFixture, SlowTestHasCorrectFailureInformation) +{ + SlowTest test; + list.Add(&test); + RunAllTests(reporter, list, 0, 3); + CHECK_EQUAL (test.m_details.testName, reporter.lastFailedTest); + CHECK (std::strstr(test.m_details.filename, reporter.lastFailedFile)); + CHECK_EQUAL (test.m_details.lineNumber, reporter.lastFailedLine); + CHECK (std::strstr(reporter.lastFailedMessage, "Global time constraint failed")); + CHECK (std::strstr(reporter.lastFailedMessage, "3ms")); +} + +TEST_FIXTURE(TestRunnerFixture, SlowTestWithTimeExemptionPasses) +{ + class SlowExemptedTest : public Test + { + public: + SlowExemptedTest() : Test("slowexempted", "", 0) {} + virtual void RunImpl(TestResults&) const + { + UNITTEST_TIME_CONSTRAINT_EXEMPT(); + TimeHelpers::SleepMs(20); + } + }; + + SlowExemptedTest test; + list.Add(&test); + RunAllTests(reporter, list, 0, 3); + CHECK_EQUAL (0, reporter.testFailedCount); +} + +struct TestSuiteFixture +{ + TestSuiteFixture() + : test1("TestInDefaultSuite") + , test2("TestInOtherSuite", "OtherSuite") + , test3("SecondTestInDefaultSuite") + { + list.Add(&test1); + list.Add(&test2); + } + + Test test1; + Test test2; + Test test3; + RecordingReporter reporter; + TestList list; +}; + +TEST_FIXTURE(TestSuiteFixture, TestRunnerRunsAllSuitesIfNullSuiteIsPassed) +{ + RunAllTests(reporter, list, 0); + CHECK_EQUAL(2, reporter.summaryTotalTestCount); +} + +TEST_FIXTURE(TestSuiteFixture,TestRunnerRunsOnlySpecifiedSuite) +{ + RunAllTests(reporter, list, "OtherSuite"); + CHECK_EQUAL(1, reporter.summaryTotalTestCount); + CHECK_EQUAL("TestInOtherSuite", reporter.lastFinishedTest); +} + + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTestSuite.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTestSuite.cpp new file mode 100644 index 00000000..ec743a00 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTestSuite.cpp @@ -0,0 +1,13 @@ +#include + +// We're really testing if it's possible to use the same suite in two files +// to compile and link successfuly (TestTestSuite.cpp has suite with the same name) +// Note: we are outside of the anonymous namespace +SUITE(SameTestSuite) +{ + TEST(DummyTest2) + { + (void)testResults_; + } +} + diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraint.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraint.cpp new file mode 100644 index 00000000..19441a4c --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraint.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include "RecordingReporter.h" + +using namespace UnitTest; + +namespace +{ + +TEST(TimeConstraintSucceedsWithFastTest) +{ + TestResults result; + { + TimeConstraint t(200, result, TestDetails("", "", "", 0)); + TimeHelpers::SleepMs(5); + } + CHECK_EQUAL(0, result.GetFailureCount()); +} + +TEST(TimeConstraintFailsWithSlowTest) +{ + TestResults result; + { + TimeConstraint t(10, result, TestDetails("", "", "", 0)); + TimeHelpers::SleepMs(20); + } + CHECK_EQUAL(1, result.GetFailureCount()); +} + +TEST(TimeConstraintFailureIncludesCorrectData) +{ + RecordingReporter reporter; + TestResults result(&reporter); + { + TestDetails const details("testname", "suitename", "filename", 10); + TimeConstraint t(10, result, details); + TimeHelpers::SleepMs(20); + } + CHECK(std::strstr(reporter.lastFailedFile, "filename")); + CHECK_EQUAL(10, reporter.lastFailedLine); + CHECK(std::strstr(reporter.lastFailedTest, "testname")); +} + +TEST(TimeConstraintFailureIncludesTimeoutInformation) +{ + RecordingReporter reporter; + TestResults result(&reporter); + { + TimeConstraint t(10, result, TestDetails("", "", "", 0)); + TimeHelpers::SleepMs(20); + } + CHECK(std::strstr(reporter.lastFailedMessage, "ime constraint")); + CHECK(std::strstr(reporter.lastFailedMessage, "under 10ms")); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraintMacro.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraintMacro.cpp new file mode 100644 index 00000000..dee1b5d6 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraintMacro.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include "RecordingReporter.h" + +namespace { + +TEST (TimeConstraintMacroQualifiesNamespace) +{ + // If this compiles without a "using namespace UnitTest;", all is well. + UNITTEST_TIME_CONSTRAINT(1); +} + +TEST (TimeConstraintMacroUsesCorrectInfo) +{ + int testLine = 0; + RecordingReporter reporter; + { + UnitTest::TestResults testResults_(&reporter); + UNITTEST_TIME_CONSTRAINT(10); testLine = __LINE__; + UnitTest::TimeHelpers::SleepMs(20); + } + CHECK_EQUAL (1, reporter.testFailedCount); + CHECK (std::strstr(reporter.lastFailedFile, __FILE__)); + CHECK_EQUAL (testLine, reporter.lastFailedLine); + CHECK (std::strstr(reporter.lastFailedTest, "TimeConstraintMacroUsesCorrectInfo")); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestUnitTest++.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestUnitTest++.cpp new file mode 100644 index 00000000..1574ae21 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestUnitTest++.cpp @@ -0,0 +1,137 @@ +#include +#include + +#include + +// These are sample tests that show the different features of the framework + +namespace { + +TEST(ValidCheckSucceeds) +{ + bool const b = true; + CHECK(b); +} + +TEST(CheckWorksWithPointers) +{ + void* p = (void *)0x100; + CHECK(p); + CHECK(p != 0); +} + +TEST(ValidCheckEqualSucceeds) +{ + int const x = 3; + int const y = 3; + CHECK_EQUAL(x, y); +} + +TEST(CheckEqualWorksWithPointers) +{ + void* p = (void *)0; + CHECK_EQUAL ((void*)0, p); +} + +TEST(ValidCheckCloseSucceeds) +{ + CHECK_CLOSE(2.0f, 2.001f, 0.01f); + CHECK_CLOSE(2.001f, 2.0f, 0.01f); +} + +TEST(ArrayCloseSucceeds) +{ + float const a1[] = {1, 2, 3}; + float const a2[] = {1, 2.01f, 3}; + CHECK_ARRAY_CLOSE (a1, a2, 3, 0.1f); +} + +TEST (CheckArrayCloseWorksWithVectors) +{ + std::vector< float > a(4); + for (int i = 0; i < 4; ++i) + a[i] = (float)i; + + CHECK_ARRAY_CLOSE (a, a, (int)a.size(), 0.0001f); +} + +TEST(CheckThrowMacroSucceedsOnCorrectException) +{ + struct TestException {}; + CHECK_THROW(throw TestException(), TestException); +} + +TEST(CheckAssertSucceeds) +{ + CHECK_ASSERT(UnitTest::ReportAssert("desc", "file", 0)); +} + +TEST(CheckThrowMacroFailsOnMissingException) +{ + class NoThrowTest : public UnitTest::Test + { + public: + NoThrowTest() : Test("nothrow") {} + void DontThrow() const + { + } + + virtual void RunImpl(UnitTest::TestResults& testResults_) const + { + CHECK_THROW(DontThrow(), int); + } + }; + + UnitTest::TestResults results; + + NoThrowTest const test; + test.Run(results); + CHECK_EQUAL(1, results.GetFailureCount()); +} + +TEST(CheckThrowMacroFailsOnWrongException) +{ + class WrongThrowTest : public UnitTest::Test + { + public: + WrongThrowTest() : Test("wrongthrow") {} + virtual void RunImpl(UnitTest::TestResults& testResults_) const + { + CHECK_THROW(throw "oops", int); + } + }; + + UnitTest::TestResults results; + + WrongThrowTest const test; + test.Run(results); + CHECK_EQUAL(1, results.GetFailureCount()); +} + +struct SimpleFixture +{ + SimpleFixture() + { + ++instanceCount; + } + ~SimpleFixture() + { + --instanceCount; + } + + static int instanceCount; +}; + +int SimpleFixture::instanceCount = 0; + +TEST_FIXTURE(SimpleFixture, DefaultFixtureCtorIsCalled) +{ + CHECK(SimpleFixture::instanceCount > 0); +} + +TEST_FIXTURE(SimpleFixture, OnlyOneFixtureAliveAtATime) +{ + CHECK_EQUAL(1, SimpleFixture::instanceCount); +} + +} diff --git a/avango-unittest/src/avango/UnitTest++/tests/TestXmlTestReporter.cpp b/avango-unittest/src/avango/UnitTest++/tests/TestXmlTestReporter.cpp new file mode 100644 index 00000000..87a2f795 --- /dev/null +++ b/avango-unittest/src/avango/UnitTest++/tests/TestXmlTestReporter.cpp @@ -0,0 +1,183 @@ +#include +#include + +#include + +using namespace UnitTest; +using std::ostringstream; + +namespace +{ + +#ifdef UNITTEST_USE_CUSTOM_STREAMS + +// Overload to let MemoryOutStream accept std::string +MemoryOutStream& operator<<(MemoryOutStream& s, const std::string& value) +{ + s << value.c_str(); + return s; +} + +#endif + +struct XmlTestReporterFixture +{ + XmlTestReporterFixture() + : reporter(output) + { + } + + ostringstream output; + XmlTestReporter reporter; +}; + +TEST_FIXTURE(XmlTestReporterFixture, MultipleCharactersAreEscaped) +{ + TestDetails const details("TestName", "suite", "filename.h", 4321); + + reporter.ReportTestStart(details); + reporter.ReportFailure(details, "\"\"\'\'&&<<>>"); + reporter.ReportTestFinish(details, 0.1f); + reporter.ReportSummary(1, 2, 3, 0.1f); + + char const* expected = + "" + "" + "" + "" + "" + ""; + + CHECK_EQUAL(expected, output.str()); +} + +TEST_FIXTURE(XmlTestReporterFixture, OutputIsCachedUntilReportSummaryIsCalled) +{ + TestDetails const details("", "", "", 0); + + reporter.ReportTestStart(details); + reporter.ReportFailure(details, "message"); + reporter.ReportTestFinish(details, 1.0F); + CHECK(output.str().empty()); + + reporter.ReportSummary(1, 1, 1, 1.0f); + CHECK(!output.str().empty()); +} + +TEST_FIXTURE(XmlTestReporterFixture, EmptyReportSummaryFormat) +{ + reporter.ReportSummary(0, 0, 0, 0.1f); + + const char *expected = +"" +"" +""; + + CHECK_EQUAL(expected, output.str()); +} + +TEST_FIXTURE(XmlTestReporterFixture, SingleSuccessfulTestReportSummaryFormat) +{ + TestDetails const details("TestName", "DefaultSuite", "", 0); + + reporter.ReportTestStart(details); + reporter.ReportSummary(1, 0, 0, 0.1f); + + const char *expected = +"" +"" +"" +""; + + CHECK_EQUAL(expected, output.str()); +} + +TEST_FIXTURE(XmlTestReporterFixture, SingleFailedTestReportSummaryFormat) +{ + TestDetails const details("A Test", "suite", "A File", 4321); + + reporter.ReportTestStart(details); + reporter.ReportFailure(details, "A Failure"); + reporter.ReportSummary(1, 1, 1, 0.1f); + + const char *expected = + "" + "" + "" + "" + "" + ""; + + CHECK_EQUAL(expected, output.str()); +} + +TEST_FIXTURE(XmlTestReporterFixture, FailureMessageIsXMLEscaped) +{ + TestDetails const details("TestName", "suite", "filename.h", 4321); + + reporter.ReportTestStart(details); + reporter.ReportFailure(details, "\"\'&<>"); + reporter.ReportTestFinish(details, 0.1f); + reporter.ReportSummary(1, 1, 1, 0.1f); + + char const* expected = + "" + "" + "" + "" + "" + ""; + + CHECK_EQUAL(expected, output.str()); +} + +TEST_FIXTURE(XmlTestReporterFixture, OneFailureAndOneSuccess) +{ + TestDetails const failedDetails("FailedTest", "suite", "fail.h", 1); + reporter.ReportTestStart(failedDetails); + reporter.ReportFailure(failedDetails, "expected 1 but was 2"); + reporter.ReportTestFinish(failedDetails, 0.1f); + + TestDetails const succeededDetails("SucceededTest", "suite", "", 0); + reporter.ReportTestStart(succeededDetails); + reporter.ReportTestFinish(succeededDetails, 1.0f); + reporter.ReportSummary(2, 1, 1, 1.1f); + + char const* expected = + "" + "" + "" + "" + "" + "" + ""; + + CHECK_EQUAL(expected, output.str()); +} + +TEST_FIXTURE(XmlTestReporterFixture, MultipleFailures) +{ + TestDetails const failedDetails1("FailedTest", "suite", "fail.h", 1); + TestDetails const failedDetails2("FailedTest", "suite", "fail.h", 31); + + reporter.ReportTestStart(failedDetails1); + reporter.ReportFailure(failedDetails1, "expected 1 but was 2"); + reporter.ReportFailure(failedDetails2, "expected one but was two"); + reporter.ReportTestFinish(failedDetails1, 0.1f); + + reporter.ReportSummary(1, 1, 2, 1.1f); + + char const* expected = + "" + "" + "" + "" + "" + "" + ""; + + CHECK_EQUAL(expected, output.str()); +} + +} diff --git a/cmake/modules/find_boost.cmake b/cmake/modules/find_boost.cmake new file mode 100644 index 00000000..9016a1ac --- /dev/null +++ b/cmake/modules/find_boost.cmake @@ -0,0 +1,166 @@ +SET(AVANGO_BOOST_MIN_VERSION_MAJOR 1) +SET(AVANGO_BOOST_MIN_VERSION_MINOR 46) +SET(AVANGO_BOOST_MIN_VERSION_SUBMINOR 0) +SET(AVANGO_BOOST_MIN_VERSION "${AVANGO_BOOST_MIN_VERSION_MAJOR}.${AVANGO_BOOST_MIN_VERSION_MINOR}.${AVANGO_BOOST_MIN_VERSION_SUBMINOR}") +MATH(EXPR AVANGO_BOOST_MIN_VERSION_NUM "${AVANGO_BOOST_MIN_VERSION_MAJOR}*10000 + ${AVANGO_BOOST_MIN_VERSION_MINOR}*100 + ${AVANGO_BOOST_MIN_VERSION_SUBMINOR}") + +SET(AVANGO_BOOST_INCLUDE_SEARCH_DIRS + ${GLOBAL_EXT_DIR}/inc/boost + /opt/boost/latest/include + ${CMAKE_SYSTEM_INCLUDE_PATH} + ${CMAKE_INCLUDE_PATH} + /usr/include +) + +SET(AVANGO_BOOST_LIBRARY_SEARCH_DIRS + ${GLOBAL_EXT_DIR}/lib + /opt/boost/latest/lib + ${CMAKE_SYSTEM_LIBRARY_PATH} + ${CMAKE_LIBRARY_PATH} + /usr/lib64 +) + +message("-- checking for BOOST") + +IF (NOT BOOST_INCLUDE_DIRS) + + SET(_AVANGO_BOOST_FOUND_INC_DIRS "") + FOREACH(_SEARCH_DIR ${AVANGO_BOOST_INCLUDE_SEARCH_DIRS}) + FIND_PATH(_CUR_SEARCH + NAMES boost/config.hpp + PATHS ${_SEARCH_DIR} + NO_DEFAULT_PATH) + IF (_CUR_SEARCH) + LIST(APPEND _AVANGO_BOOST_FOUND_INC_DIRS ${_CUR_SEARCH}) + ENDIF(_CUR_SEARCH) + SET(_CUR_SEARCH _CUR_SEARCH-NOTFOUND CACHE INTERNAL "internal use") + ENDFOREACH(_SEARCH_DIR ${AVANGO_BOOST_INCLUDE_SEARCH_DIRS}) + + IF (NOT _AVANGO_BOOST_FOUND_INC_DIRS) + MESSAGE(FATAL_ERROR "guacamole_boost.cmake: unable to find boost library") + ELSE (NOT _AVANGO_BOOST_FOUND_INC_DIRS) + SET(BOOST_INCLUDE_DIRS ${_AVANGO_BOOST_FOUND_INC_DIRS}) + ENDIF (NOT _AVANGO_BOOST_FOUND_INC_DIRS) + + SET(AVANGO_BOOST_VERSION 0) + SET(AVANGO_BOOST_LIB_VERSION "") + SET(AVANGO_BOOST_LIB_SUFFIX "") + + SET(_AVANGO_BOOST_CUR_VERSION ${AVANGO_BOOST_MIN_VERSION_NUM}) + + FOREACH(_INC_DIR ${_AVANGO_BOOST_FOUND_INC_DIRS}) + FILE(READ "${_INC_DIR}/boost/version.hpp" _AVANGO_BOOST_VERSION_CONTENTS) + + STRING(REGEX REPLACE ".*#define BOOST_VERSION ([0-9]+).*" "\\1" _BOOST_VERSION "${_AVANGO_BOOST_VERSION_CONTENTS}") + STRING(REGEX REPLACE ".*#define BOOST_LIB_VERSION \"([0-9_]+)\".*" "\\1" _BOOST_LIB_VERSION "${_AVANGO_BOOST_VERSION_CONTENTS}") + + IF(NOT "${_BOOST_VERSION}" STREQUAL "0") + MATH(EXPR _BOOST_MAJOR_VERSION "${_BOOST_VERSION} / 100000") + MATH(EXPR _BOOST_MINOR_VERSION "${_BOOST_VERSION} / 100 % 1000") + MATH(EXPR _BOOST_SUBMINOR_VERSION "${_BOOST_VERSION} % 100") + ELSE (NOT "${_BOOST_VERSION}" STREQUAL "0") + MESSAGE("WTF") + ENDIF(NOT "${_BOOST_VERSION}" STREQUAL "0") + + MATH(EXPR _BOOST_VERSION_NUM "${_BOOST_MAJOR_VERSION}*10000 + ${_BOOST_MINOR_VERSION}*100 + ${_BOOST_SUBMINOR_VERSION}") + + IF ( _AVANGO_BOOST_CUR_VERSION LESS _BOOST_VERSION_NUM + OR _AVANGO_BOOST_CUR_VERSION EQUAL _BOOST_VERSION_NUM) + SET(AVANGO_BOOST_VERSION ${_BOOST_VERSION}) + SET(AVANGO_BOOST_LIB_VERSION ${_BOOST_LIB_VERSION}) + SET(AVANGO_BOOST_LIB_SUFFIX ".${_BOOST_MAJOR_VERSION}.${_BOOST_MINOR_VERSION}.${_BOOST_SUBMINOR_VERSION}") + SET(BOOST_INCLUDE_DIRS ${_INC_DIR}) + SET(_AVANGO_BOOST_CUR_VERSION ${_BOOST_VERSION_NUM}) + ENDIF ( _AVANGO_BOOST_CUR_VERSION LESS _BOOST_VERSION_NUM + OR _AVANGO_BOOST_CUR_VERSION EQUAL _BOOST_VERSION_NUM) + + ENDFOREACH(_INC_DIR ${_AVANGO_BOOST_FOUND_INC_DIRS}) + + IF (AVANGO_BOOST_VERSION EQUAL 0) + MESSAGE(FATAL_ERROR "found boost versions ${_BOOST_VERSION} to old (min. version ${AVANGO_BOOST_MIN_VERSION} required)") + ELSE (AVANGO_BOOST_VERSION EQUAL 0) + #SET(BOOST_INCLUDE_DIRS ${BOOST_INCLUDE_DIRS} CACHE STRING "The boost include directory") + SET(BOOST_INCLUDE_DIRS ${BOOST_INCLUDE_DIRS}) + SET(AVANGO_BOOST_VERSION ${AVANGO_BOOST_VERSION} CACHE STRING "The boost version number") + SET(AVANGO_BOOST_LIB_SUFFIX ${AVANGO_BOOST_LIB_SUFFIX} CACHE STRING "The boost library suffix") + SET(AVANGO_BOOST_LIB_VERSION ${AVANGO_BOOST_LIB_VERSION} CACHE STRING "The boost library version string") + ENDIF (AVANGO_BOOST_VERSION EQUAL 0) + +ENDIF(NOT BOOST_INCLUDE_DIRS) + +IF ( BOOST_INCLUDE_DIRS + AND NOT BOOST_LIBRARIES) + #AND NOT BOOST_LIBRARY_DIRS) + + SET(_AVANGO_BOOST_FILESYSTEM_LIB "") + SET(_AVANGO_BOOST_FOUND_LIB_DIR "") + SET(_AVANGO_BOOST_POSTFIX "") + + if (UNIX) + LIST(APPEND _AVANGO_BOOST_FILESYSTEM_LIB "${CMAKE_SHARED_LIBRARY_PREFIX}boost_filesystem${COMPILER_SUFFIX}${AVANGO_BOOST_LIB_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}${AVANGO_BOOST_LIB_SUFFIX}" + "${CMAKE_SHARED_LIBRARY_PREFIX}boost_filesystem${CMAKE_SHARED_LIBRARY_SUFFIX}${AVANGO_BOOST_LIB_SUFFIX}" + "${CMAKE_SHARED_LIBRARY_PREFIX}boost_filesystem${CMAKE_SHARED_LIBRARY_SUFFIX}${AVANGO_BOOST_LIB_SUFFIX}") + elseif (WIN32) + LIST(APPEND _AVANGO_BOOST_FILESYSTEM_LIB "${CMAKE_STATIC_LIBRARY_PREFIX}libboost_filesystem-${COMPILER_SUFFIX}-mt-${AVANGO_BOOST_LIB_VERSION}${CMAKE_STATIC_LIBRARY_SUFFIX}" + "${CMAKE_STATIC_LIBRARY_PREFIX}libboost_filesystem-mt${CMAKE_STATIC_LIBRARY_SUFFIX}") + endif (UNIX) + + + FOREACH(_SEARCH_DIR ${AVANGO_BOOST_LIBRARY_SEARCH_DIRS}) + FIND_PATH(_CUR_SEARCH + NAMES ${_AVANGO_BOOST_FILESYSTEM_LIB} + PATHS ${_SEARCH_DIR} + PATH_SUFFIXES debug release . + NO_DEFAULT_PATH) + IF (_CUR_SEARCH) + LIST(APPEND _AVANGO_BOOST_FOUND_LIB_DIR ${_SEARCH_DIR}) + if (UNIX) + FIND_FILE(_CUR_SEARCH_FILE NAMES ${_AVANGO_BOOST_FILESYSTEM_LIB} PATHS ${_CUR_SEARCH}) + if (_CUR_SEARCH_FILE) + LIST(APPEND BOOST_LIBRARIES ${_CUR_SEARCH_FILE}) + STRING(REGEX REPLACE "${_CUR_SEARCH}/${CMAKE_SHARED_LIBRARY_PREFIX}boost_filesystem(.*).so(.*)" "\\2" _AVANGO_BOOST_UNIX_LIB_SUF ${_CUR_SEARCH_FILE}) + if (${_AVANGO_BOOST_UNIX_LIB_SUF} STREQUAL ${AVANGO_BOOST_LIB_SUFFIX}) + message("found matching version") + list(APPEND BOOST_LIBRARIES _AVANGO_BOOST_FILESYSTEM_LIB) + STRING(REGEX REPLACE "${_CUR_SEARCH}/${CMAKE_SHARED_LIBRARY_PREFIX}boost_filesystem(.*).so(.*)" "\\1" _AVANGO_BOOST_POSTFIX ${_CUR_SEARCH_FILE}) + endif (${_AVANGO_BOOST_UNIX_LIB_SUF} STREQUAL ${AVANGO_BOOST_LIB_SUFFIX}) + endif (_CUR_SEARCH_FILE) + SET(_CUR_SEARCH_FILE _CUR_SEARCH_FILE-NOTFOUND CACHE INTERNAL "internal use") + endif (UNIX) + ENDIF(_CUR_SEARCH) + SET(_CUR_SEARCH _CUR_SEARCH-NOTFOUND CACHE INTERNAL "internal use") + ENDFOREACH(_SEARCH_DIR ${AVANGO_BOOST_LIBRARY_SEARCH_DIRS}) + + IF (NOT _AVANGO_BOOST_FOUND_LIB_DIR) + MESSAGE(FATAL_ERROR "guacamole_boost.cmake: unable to find boost library") + ELSE (NOT _AVANGO_BOOST_FOUND_LIB_DIR) + SET(BOOST_LIBRARY_DIRS ${_AVANGO_BOOST_FOUND_LIB_DIR} CACHE STRING "The boost library directory") + message("-- found matching version") + FILE(GLOB BOOST_LIBRARIES ${_AVANGO_BOOST_FOUND_LIB_DIR}/*.so) + ENDIF (NOT _AVANGO_BOOST_FOUND_LIB_DIR) + + if (UNIX) +# SET(SCHISM_BOOST_LIB_POSTFIX_REL "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "(deprecated) boost library release postfix") +# SET(SCHISM_BOOST_LIB_POSTFIX_DBG "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "(deprecated) boost library debug postfix") +# IF (NOT _AVANGO_BOOST_POSTFIX) +# MESSAGE(FATAL_ERROR "guacamole_boost.cmake: unable to determine boost library suffix") +# ELSE (NOT _AVANGO_BOOST_POSTFIX) +# SET(SCHISM_BOOST_LIB_POSTFIX_REL "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "boost library release postfix") +# SET(SCHISM_BOOST_LIB_POSTFIX_DBG "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "boost library debug postfix") +# ENDIF (NOT _AVANGO_BOOST_POSTFIX) + set(AVANGO_BOOST_MT_REL "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "boost dynamic library release postfix") + set(AVANGO_BOOST_MT_DBG "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "boost dynamic library debug postfix") + set(AVANGO_BOOST_MT_S_REL "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "boost static library release postfix") + set(AVANGO_BOOST_MT_S_DBG "${_AVANGO_BOOST_POSTFIX}" CACHE STRING "boost static library debug postfix") + elseif (WIN32) +# SET(SCHISM_BOOST_LIB_POSTFIX_REL "${COMPILER_SUFFIX}-mt-${AVANGO_BOOST_LIB_VERSION}" CACHE STRING "(deprecated) boost library release postfix") +# SET(SCHISM_BOOST_LIB_POSTFIX_DBG "${COMPILER_SUFFIX}-mt-gd-${AVANGO_BOOST_LIB_VERSION}" CACHE STRING "(deprecated) boost library debug postfix") + + set(AVANGO_BOOST_MT_REL "${COMPILER_SUFFIX}-mt-${AVANGO_BOOST_LIB_VERSION}" CACHE STRING "boost dynamic library release postfix") + set(AVANGO_BOOST_MT_DBG "${COMPILER_SUFFIX}-mt-gd-${AVANGO_BOOST_LIB_VERSION}" CACHE STRING "boost dynamic library debug postfix") + set(AVANGO_BOOST_MT_S_REL "${COMPILER_SUFFIX}-mt-s-${AVANGO_BOOST_LIB_VERSION}" CACHE STRING "boost static library release postfix") + set(AVANGO_BOOST_MT_S_DBG "${COMPILER_SUFFIX}-mt-sgd-${AVANGO_BOOST_LIB_VERSION}" CACHE STRING "boost static library debug postfix") + endif (UNIX) + +ENDIF(BOOST_INCLUDE_DIRS AND NOT BOOST_LIBRARIES) +# AND NOT BOOST_LIBRARY_DIRS) diff --git a/cmake/modules/find_compiler.cmake b/cmake/modules/find_compiler.cmake new file mode 100644 index 00000000..866622f0 --- /dev/null +++ b/cmake/modules/find_compiler.cmake @@ -0,0 +1,47 @@ +if (WIN32) + if (MSVC71) + set (COMPILER_SUFFIX "vc71") + endif(MSVC71) + + if (MSVC80) + set (COMPILER_SUFFIX "vc80") + endif(MSVC80) + + if (MSVC90) + set (COMPILER_SUFFIX "vc90") + endif(MSVC90) + + if (MSVC10) + set (COMPILER_SUFFIX "vc100") + endif(MSVC10) + + if (MSVC11) + set (COMPILER_SUFFIX "vc110") + endif(MSVC11) + + if (MSVC12) + set (COMPILER_SUFFIX "vc120") + endif(MSVC12) +endif (WIN32) + +if (UNIX) + if (CMAKE_COMPILER_IS_GNUCXX) + #find out the version of gcc being used. + exec_program(${CMAKE_CXX_COMPILER} + ARGS --version + OUTPUT_VARIABLE _COMPILER_VERSION + ) + message(${_COMPILER_VERSION}) + string(REGEX REPLACE ".* ([0-9])\\.([0-9])\\.[0-9].*" "\\1\\2" _COMPILER_VERSION ${_COMPILER_VERSION}) + message(${_COMPILER_VERSION}) + set (COMPILER_SUFFIX "gcc${_COMPILER_VERSION}") + #set (COMPILER_SUFFIX "") + message(${COMPILER_SUFFIX}) + endif (CMAKE_COMPILER_IS_GNUCXX) +endif(UNIX) + +if (COMPILER_SUFFIX STREQUAL "") + message(FATAL_ERROR "schism_compiler.cmake: unable to identify supported compiler") +else (COMPILER_SUFFIX STREQUAL "") + set(COMPILER_SUFFIX ${COMPILER_SUFFIX} CACHE STRING "The boost style compiler suffix") +endif (COMPILER_SUFFIX STREQUAL "") From 6b7ffeac8544b46ec418ede9ece9bce5554b28f7 Mon Sep 17 00:00:00 2001 From: Andreas-Christoph Bernstein Date: Mon, 4 Nov 2013 13:04:02 +0100 Subject: [PATCH 03/96] ignore files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 620d3dc8..a49e91b1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,7 @@ *.lai *.la *.a + +CMakeCache.txt +cmake_install.cmake +Makefile From 0ba45087df8f5f5285e28041b118ab364e32d659 Mon Sep 17 00:00:00 2001 From: Andre Schollmeyer Date: Mon, 4 Nov 2013 16:35:01 +0100 Subject: [PATCH 04/96] -removed old unittest version --- avango-python/include/avango/python/Doxygen.h | 44 ++ .../include/avango/python/exceptions.h | 50 ++ .../include/avango/python/register_field.h | 234 ++++++ .../include/avango/python/script/Init.h | 52 ++ .../include/avango/python/script/Script.h | 85 +++ .../include/avango/python/script/Types.h | 78 ++ .../avango/python/windows_specific_python.h | 44 ++ avango-python/src/avango/Field.cpp | 148 ++++ avango-python/src/avango/Field.h | 27 + avango-python/src/avango/FieldContainer.cpp | 187 +++++ avango-python/src/avango/FieldContainer.h | 39 + avango-python/src/avango/InputStream.cpp | 72 ++ avango-python/src/avango/InputStream.h | 27 + avango-python/src/avango/OutputStream.cpp | 74 ++ avango-python/src/avango/OutputStream.h | 27 + avango-python/src/avango/__init__.py | 81 ++ avango-python/src/avango/_avango.cpp | 151 ++++ avango-python/src/avango/_fieldcontainer.py | 56 ++ avango-python/src/avango/_utility.py | 56 ++ avango-python/src/avango/exceptions.cpp | 31 + avango-python/src/avango/nodefactory.py | 60 ++ avango-python/src/avango/script/Init.cpp | 49 ++ avango-python/src/avango/script/Script.cpp | 244 ++++++ avango-python/src/avango/script/Types.cpp | 63 ++ avango-python/src/avango/script/Update.cpp | 74 ++ avango-python/src/avango/script/Update.h | 59 ++ avango-python/src/avango/script/__init__.py | 29 + avango-python/src/avango/script/_container.py | 48 ++ .../src/avango/script/_meta_script.py | 143 ++++ avango-python/src/avango/script/_script.cpp | 34 + .../src/tests/MockFieldContainer.cpp | 62 ++ avango-python/src/tests/MockFieldContainer.h | 81 ++ avango-python/src/tests/TestContainer.py | 66 ++ avango-python/src/tests/TestField.py | 152 ++++ avango-python/src/tests/TestFieldContainer.py | 133 ++++ avango-python/src/tests/TestNodefactory.py | 57 ++ avango-python/src/tests/TestScript.py | 481 ++++++++++++ avango-python/src/tests/TestUpdate.py | 71 ++ avango-python/src/tests/TestUtility.py | 76 ++ .../src/tests/_mockfieldcontainer.cpp | 47 ++ avango-python/src/tests/apackage/__init__.py | 23 + avango-python/src/tests/apackage/empty.py | 29 + avango-python/src/tests/mock.py | 27 + avango-python/src/tests/runtests.py | 47 ++ avango-unittest/CMakeLists.txt | 136 +--- .../dist/pkg-config/avango-unittest.pc.in | 10 - .../avango/UnitTest++/AssertException.h | 28 - .../include/avango/UnitTest++/CheckMacros.h | 102 --- .../include/avango/UnitTest++/Checks.h | 146 ---- .../include/avango/UnitTest++/Config.h | 25 - .../avango/UnitTest++/DeferredTestReporter.h | 28 - .../avango/UnitTest++/DeferredTestResult.h | 29 - .../avango/UnitTest++/MemoryOutStream.h | 67 -- .../UnitTest++/Posix/SignalTranslator.h | 42 -- .../avango/UnitTest++/Posix/TimeHelpers.h | 28 - .../include/avango/UnitTest++/ReportAssert.h | 10 - .../include/avango/UnitTest++/Test.h | 34 - .../include/avango/UnitTest++/TestDetails.h | 24 - .../include/avango/UnitTest++/TestList.h | 32 - .../include/avango/UnitTest++/TestMacros.h | 99 --- .../include/avango/UnitTest++/TestReporter.h | 20 - .../avango/UnitTest++/TestReporterStdout.h | 19 - .../include/avango/UnitTest++/TestResults.h | 36 - .../include/avango/UnitTest++/TestRunner.h | 17 - .../include/avango/UnitTest++/TestSuite.h | 14 - .../avango/UnitTest++/TimeConstraint.h | 34 - .../include/avango/UnitTest++/TimeHelpers.h | 7 - .../include/avango/UnitTest++/UnitTest++.h | 17 - .../avango/UnitTest++/Win32/TimeHelpers.h | 48 -- .../avango/UnitTest++/XmlTestReporter.h | 34 - .../src/avango/UnitTest++/AssertException.cpp | 32 - avango-unittest/src/avango/UnitTest++/COPYING | 20 - .../src/avango/UnitTest++/Checks.cpp | 48 -- .../UnitTest++/DeferredTestReporter.cpp | 28 - .../avango/UnitTest++/DeferredTestResult.cpp | 26 - .../src/avango/UnitTest++/MemoryOutStream.cpp | 143 ---- .../UnitTest++/Posix/SignalTranslator.cpp | 46 -- .../avango/UnitTest++/Posix/TimeHelpers.cpp | 33 - avango-unittest/src/avango/UnitTest++/README | 57 -- .../src/avango/UnitTest++/ReportAssert.cpp | 12 - .../src/avango/UnitTest++/Test.cpp | 62 -- .../src/avango/UnitTest++/TestDetails.cpp | 22 - .../src/avango/UnitTest++/TestList.cpp | 39 - .../src/avango/UnitTest++/TestReporter.cpp | 10 - .../avango/UnitTest++/TestReporterStdout.cpp | 36 - .../src/avango/UnitTest++/TestResults.cpp | 60 -- .../src/avango/UnitTest++/TestRunner.cpp | 60 -- .../src/avango/UnitTest++/TimeConstraint.cpp | 28 - .../avango/UnitTest++/Win32/TimeHelpers.cpp | 46 -- .../src/avango/UnitTest++/XmlTestReporter.cpp | 126 ---- .../avango/UnitTest++/docs/UnitTest++.html | 260 ------- .../src/avango/UnitTest++/tests/Main.cpp | 8 - .../UnitTest++/tests/RecordingReporter.h | 92 --- .../UnitTest++/tests/TestAssertHandler.cpp | 44 -- .../UnitTest++/tests/TestCheckMacros.cpp | 710 ------------------ .../avango/UnitTest++/tests/TestChecks.cpp | 290 ------- .../tests/TestDeferredTestReporter.cpp | 104 --- .../UnitTest++/tests/TestMemoryOutStream.cpp | 150 ---- .../src/avango/UnitTest++/tests/TestTest.cpp | 97 --- .../avango/UnitTest++/tests/TestTestList.cpp | 50 -- .../UnitTest++/tests/TestTestMacros.cpp | 171 ----- .../UnitTest++/tests/TestTestResults.cpp | 111 --- .../UnitTest++/tests/TestTestRunner.cpp | 233 ------ .../avango/UnitTest++/tests/TestTestSuite.cpp | 13 - .../UnitTest++/tests/TestTimeConstraint.cpp | 57 -- .../tests/TestTimeConstraintMacro.cpp | 29 - .../UnitTest++/tests/TestUnitTest++.cpp | 137 ---- .../UnitTest++/tests/TestXmlTestReporter.cpp | 183 ----- 108 files changed, 3726 insertions(+), 4751 deletions(-) create mode 100644 avango-python/include/avango/python/Doxygen.h create mode 100644 avango-python/include/avango/python/exceptions.h create mode 100644 avango-python/include/avango/python/register_field.h create mode 100644 avango-python/include/avango/python/script/Init.h create mode 100644 avango-python/include/avango/python/script/Script.h create mode 100644 avango-python/include/avango/python/script/Types.h create mode 100644 avango-python/include/avango/python/windows_specific_python.h create mode 100644 avango-python/src/avango/Field.cpp create mode 100644 avango-python/src/avango/Field.h create mode 100644 avango-python/src/avango/FieldContainer.cpp create mode 100644 avango-python/src/avango/FieldContainer.h create mode 100644 avango-python/src/avango/InputStream.cpp create mode 100644 avango-python/src/avango/InputStream.h create mode 100644 avango-python/src/avango/OutputStream.cpp create mode 100644 avango-python/src/avango/OutputStream.h create mode 100644 avango-python/src/avango/__init__.py create mode 100644 avango-python/src/avango/_avango.cpp create mode 100644 avango-python/src/avango/_fieldcontainer.py create mode 100644 avango-python/src/avango/_utility.py create mode 100644 avango-python/src/avango/exceptions.cpp create mode 100644 avango-python/src/avango/nodefactory.py create mode 100644 avango-python/src/avango/script/Init.cpp create mode 100644 avango-python/src/avango/script/Script.cpp create mode 100644 avango-python/src/avango/script/Types.cpp create mode 100644 avango-python/src/avango/script/Update.cpp create mode 100644 avango-python/src/avango/script/Update.h create mode 100644 avango-python/src/avango/script/__init__.py create mode 100644 avango-python/src/avango/script/_container.py create mode 100644 avango-python/src/avango/script/_meta_script.py create mode 100644 avango-python/src/avango/script/_script.cpp create mode 100644 avango-python/src/tests/MockFieldContainer.cpp create mode 100644 avango-python/src/tests/MockFieldContainer.h create mode 100644 avango-python/src/tests/TestContainer.py create mode 100644 avango-python/src/tests/TestField.py create mode 100644 avango-python/src/tests/TestFieldContainer.py create mode 100644 avango-python/src/tests/TestNodefactory.py create mode 100644 avango-python/src/tests/TestScript.py create mode 100644 avango-python/src/tests/TestUpdate.py create mode 100644 avango-python/src/tests/TestUtility.py create mode 100644 avango-python/src/tests/_mockfieldcontainer.cpp create mode 100644 avango-python/src/tests/apackage/__init__.py create mode 100644 avango-python/src/tests/apackage/empty.py create mode 100644 avango-python/src/tests/mock.py create mode 100644 avango-python/src/tests/runtests.py delete mode 100644 avango-unittest/dist/pkg-config/avango-unittest.pc.in delete mode 100644 avango-unittest/include/avango/UnitTest++/AssertException.h delete mode 100644 avango-unittest/include/avango/UnitTest++/CheckMacros.h delete mode 100644 avango-unittest/include/avango/UnitTest++/Checks.h delete mode 100644 avango-unittest/include/avango/UnitTest++/Config.h delete mode 100644 avango-unittest/include/avango/UnitTest++/DeferredTestReporter.h delete mode 100644 avango-unittest/include/avango/UnitTest++/DeferredTestResult.h delete mode 100644 avango-unittest/include/avango/UnitTest++/MemoryOutStream.h delete mode 100644 avango-unittest/include/avango/UnitTest++/Posix/SignalTranslator.h delete mode 100644 avango-unittest/include/avango/UnitTest++/Posix/TimeHelpers.h delete mode 100644 avango-unittest/include/avango/UnitTest++/ReportAssert.h delete mode 100644 avango-unittest/include/avango/UnitTest++/Test.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestDetails.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestList.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestMacros.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestReporter.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestReporterStdout.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestResults.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestRunner.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TestSuite.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TimeConstraint.h delete mode 100644 avango-unittest/include/avango/UnitTest++/TimeHelpers.h delete mode 100644 avango-unittest/include/avango/UnitTest++/UnitTest++.h delete mode 100644 avango-unittest/include/avango/UnitTest++/Win32/TimeHelpers.h delete mode 100644 avango-unittest/include/avango/UnitTest++/XmlTestReporter.h delete mode 100644 avango-unittest/src/avango/UnitTest++/AssertException.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/COPYING delete mode 100644 avango-unittest/src/avango/UnitTest++/Checks.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/DeferredTestReporter.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/DeferredTestResult.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/MemoryOutStream.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/Posix/SignalTranslator.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/Posix/TimeHelpers.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/README delete mode 100644 avango-unittest/src/avango/UnitTest++/ReportAssert.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/Test.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/TestDetails.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/TestList.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/TestReporter.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/TestReporterStdout.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/TestResults.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/TestRunner.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/TimeConstraint.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/Win32/TimeHelpers.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/XmlTestReporter.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/docs/UnitTest++.html delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/Main.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/RecordingReporter.h delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestAssertHandler.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestCheckMacros.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestChecks.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestDeferredTestReporter.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestMemoryOutStream.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTest.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestList.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestMacros.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestResults.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestRunner.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTestSuite.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraint.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestTimeConstraintMacro.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestUnitTest++.cpp delete mode 100644 avango-unittest/src/avango/UnitTest++/tests/TestXmlTestReporter.cpp diff --git a/avango-python/include/avango/python/Doxygen.h b/avango-python/include/avango/python/Doxygen.h new file mode 100644 index 00000000..0a812ef2 --- /dev/null +++ b/avango-python/include/avango/python/Doxygen.h @@ -0,0 +1,44 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AVANGO_PYTHON_DOXYGEN_H) +#define AVANGO_PYTHON_DOXYGEN_H + +/** + * \defgroup av_python AVANGO Python Binding + */ + +/** + * \file + * \ingroup av_python + */ + +/** + * \namespace av::python + * AVANGO Python Binding + * + * \ingroup av_python + */ + +#endif // #if !defined(AVANGO_PYTHON_DOXYGEN_H) + diff --git a/avango-python/include/avango/python/exceptions.h b/avango-python/include/avango/python/exceptions.h new file mode 100644 index 00000000..85cff4a0 --- /dev/null +++ b/avango-python/include/avango/python/exceptions.h @@ -0,0 +1,50 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(EXCEPTIONS_H) +#define EXCEPTIONS_H + +#include + +/** + * \file + * \ingroup av_python + */ + +namespace av +{ + namespace python + { + + namespace detail + { + class index_exception {}; + + void translate(index_exception const& e); + } + + } + +} + +#endif diff --git a/avango-python/include/avango/python/register_field.h b/avango-python/include/avango/python/register_field.h new file mode 100644 index 00000000..9ff17668 --- /dev/null +++ b/avango-python/include/avango/python/register_field.h @@ -0,0 +1,234 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(REGISTER_FIELD_H) +#define REGISTER_FIELD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "exceptions.h" + +/** + * \namespace av::python + * Avango Python Library + * + * \ingroup av_python + */ + +/** + * \file + * \ingroup av_python + */ + +namespace av +{ + namespace python + { + + namespace detail + { + template struct select_link_type + { + typedef Type type; + static Type get_value(boost::python::object obj) + { + return boost::python::extract(obj); + } + }; + + template struct select_link_type< av::Link > + { + typedef Type type; + static av::Link get_value(boost::python::object obj) + { + av::Base* av_value = boost::python::extract(obj); + // FIXME Throw exception when dynamic cast fails + return av::Link(dynamic_cast(av_value)); + } + }; + + template typename Type::ValueType Field_get_value(Type& self) + { + return self.getValue(); + } + + template void Field_set_value(Type& self, boost::python::object value) + { + typedef typename Type::ValueType value_type; + value_type tmp(detail::select_link_type::get_value(value)); + self.setValue(tmp); + } + } + + template void register_field(std::string name) + { + boost::python::class_ >(name.c_str()) + .def("get_value", &Type::getValue, boost::python::return_value_policy()) + .def("set_value", detail::Field_set_value) + .add_property("value", detail::Field_get_value, detail::Field_set_value); + ; + } + + + namespace detail + { + template class MultiFieldWrapper + { + public: + MultiFieldWrapper(Type& Field) : + mField(Field) + { + } + + private: + + void validate_index(int index) + { + if ( (index < 0) || (index >= mField.getSize()) ) + throw index_exception(); + } + + typedef typename Type::ValueType ValueType; + typedef detail::select_link_type SelectType; + + public: + + int getSize(void) + { + return mField.getSize(); + } + + typename Type::ValueType getItem(int index) + { + validate_index(index); + return mField.getValue()[index]; + } + + void setItem(int index, boost::python::object value) + { + validate_index(index); + + typename Type::ContainerType container = mField.getValue(); + container[index] = SelectType::get_value(value); + mField.setValue(container); + } + + void delItem(int index) + { + validate_index(index); + + typename Type::ContainerType container = mField.getValue(); + container.erase(container.begin()+index); + mField.setValue(container); + } + + void remove(boost::python::object value) + { + mField.remove1Value(SelectType::get_value(value)); + } + + void append(boost::python::object value) + { + mField.add1Value(SelectType::get_value(value)); + } + + void extend(boost::python::object values) + { + typename Type::ContainerType container = mField.getValue(); + int len = boost::python::extract(values.attr("__len__")()); + for (int i = 0; i != len; ++i) + { + boost::python::object v = values.attr("__getitem__")(i); + container.push_back(SelectType::get_value(v)); + } + mField.setValue(container); + } + + void insert(int index, boost::python::object value) + { + validate_index(index); + + typename Type::ContainerType container = mField.getValue(); + container.insert(container.begin()+index, SelectType::get_value(value)); + mField.setValue(container); + } + + private: + Type& mField; + }; + + template MultiFieldWrapper MultiField_get_value(Type& self) + { + return MultiFieldWrapper(self); + } + + template void MultiField_set_value(Type& self, boost::python::object value) + { + typedef typename Type::ValueType value_type; + int len = boost::python::extract(value.attr("__len__")()); + std::vector list(len); + for (int i = 0; i != len; ++i) + { + boost::python::object v = value.attr("__getitem__")(i); + list[i] = detail::select_link_type::get_value(v); + } + self.setValue(list); + } + + } + + template void register_multifield(std::string name) + { + using namespace av::python::detail; + + boost::python::class_ >(name.c_str()) + .def("get_value", MultiField_get_value) + .def("set_value", MultiField_set_value) + .add_property("value", MultiField_get_value, MultiField_set_value); + ; + + boost::python::class_ >((name+"_wrapper").c_str(), boost::python::no_init) + .def("__len__", &MultiFieldWrapper::getSize) + .def("__getitem__", &MultiFieldWrapper::getItem) + .def("__setitem__", &MultiFieldWrapper::setItem) + .def("__delitem__", &MultiFieldWrapper::delItem) + .def("remove", &MultiFieldWrapper::remove) + .def("append", &MultiFieldWrapper::append) + .def("extend", &MultiFieldWrapper::extend) + .def("insert", &MultiFieldWrapper::insert) + ; + } + + } +} + + +#endif diff --git a/avango-python/include/avango/python/script/Init.h b/avango-python/include/avango/python/script/Init.h new file mode 100644 index 00000000..ebefe9a0 --- /dev/null +++ b/avango-python/include/avango/python/script/Init.h @@ -0,0 +1,52 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of Avango. * +* * +* Copyright 1997 - 2008 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* Avango is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* Avango is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with Avango. If not, see . * +* * +* Avango is a trademark owned by FhG. * +* * +\************************************************************************/ + +#if !defined(AVANGO_PYTHON_INIT_H) +#define AVANGO_PYTHON_INIT_H + +/** + * \namespace av::script + * Avango Python Library + * + * \ingroup av_python + */ + +/** + * \file + * \ingroup av_python + */ + +#include + +namespace av +{ + namespace script + { + void AV_PYTHON_DLL register_object(void); + void AV_PYTHON_DLL register_object_fields(void); + } +} // namespace av + +#endif // #if !defined(AVANGO_PYTHON_INIT_H) diff --git a/avango-python/include/avango/python/script/Script.h b/avango-python/include/avango/python/script/Script.h new file mode 100644 index 00000000..06edad9f --- /dev/null +++ b/avango-python/include/avango/python/script/Script.h @@ -0,0 +1,85 @@ +// -*- Mode:C++ -*- + +/************************************************************************\ +* * +* This file is part of AVANGO. * +* * +* Copyright 1997 - 2010 Fraunhofer-Gesellschaft zur Foerderung der * +* angewandten Forschung (FhG), Munich, Germany. * +* * +* AVANGO is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, version 3. * +* * +* AVANGO is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public * +* License along with AVANGO. If not, see . * +* * +\************************************************************************/ + +#if !defined(AV_SCRIPT_SCRIPT_H) +#define AV_SCRIPT_SCRIPT_H + +#include +#include +#include + +namespace av +{ + namespace script + { + + class AV_PYTHON_DLL Script : public av::FieldContainer, public boost::python::wrapper