ovas_main.cpp 8.73 KB
Newer Older
Jozef Legeny's avatar
Jozef Legeny committed
1 2
#include "ovasCAcquisitionServerGUI.h"

Jozef Legeny's avatar
Jozef Legeny committed
3
#include <openvibe/ov_all.h>
Jozef Legeny's avatar
Jozef Legeny committed
4
#include <toolkit/ovtk_all.h>
Jozef Legeny's avatar
Jozef Legeny committed
5 6 7 8 9

#include <gtk/gtk.h>

#include <iostream>

10 11 12 13 14
#if defined(TARGET_OS_Windows)
  #include <Windows.h>
  #include <MMSystem.h>
#endif

Jozef Legeny's avatar
Jozef Legeny committed
15 16 17 18
using namespace OpenViBE;
using namespace OpenViBE::Kernel;
using namespace std;

19 20 21 22 23 24 25 26
typedef struct _SConfiguration
{
	_SConfiguration(void)
	{
	}

	// <name, value>
	std::map < std::string, std::string > m_oFlag;
27
	std::map < std::string, std::string > m_oTokenMap;
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
} SConfiguration;

boolean parse_arguments(int argc, char** argv, SConfiguration& rConfiguration)
{
	SConfiguration l_oConfiguration;

	int i;
	std::vector < std::string > l_vArgValue;
	std::vector < std::string >::const_iterator it;
	for(i=1; i<argc; i++)
	{
		l_vArgValue.push_back(argv[i]);
	}
	l_vArgValue.push_back("");

	for(it=l_vArgValue.begin(); it!=l_vArgValue.end(); it++)
	{
		if(*it=="")
		{
		}
		else if(*it=="-c" || *it=="--config")
		{
50 51
			if(*++it=="") { std::cout << "Error: Switch --config needs an argument\n"; return false; }
			l_oConfiguration.m_oFlag["config"] = *it;
52
		}
53 54
		else if(*it=="-d" || *it=="--define")
		{
55
			if(*++it=="") {
56 57 58 59 60 61
				std::cout << "Error: Need two arguments after -d / --define.\n";
				return false;
			}

			// Were not using = as a separator for token/value, as on Windows its a problem passing = to the cmd interpreter 
			// which is used to launch the actual designer exe.
62 63
			const std::string& l_rToken = *it;
			if(*++it=="") {
64 65 66 67 68 69 70 71 72
				std::cout << "Error: Need two arguments after -d / --define.\n";
				return false;
			}

			const std::string& l_rValue = *it;	// iterator will increment later
			
			l_oConfiguration.m_oTokenMap[l_rToken] = l_rValue;

		}
73 74
		else if(*it=="-k" || *it=="--kernel")
		{
75 76
			if(*++it=="") { std::cout << "Error: Switch --kernel needs an argument\n"; return false; }
			l_oConfiguration.m_oFlag["kernel"] = *it;
77 78 79 80 81 82 83
		}
		else if(*it=="-h" || *it=="--help")
		{
			return false;
		}
		else
		{
84 85
			// The argument may be relevant to GTK, do not stop here
			std::cout << "Note: Unknown argument [" << *it << "], passing it on to gtk...\n";
86 87 88 89 90 91 92 93 94
		}
	}

	rConfiguration=l_oConfiguration;

	return true;
}


Jozef Legeny's avatar
Jozef Legeny committed
95 96 97 98 99
int main(int argc, char ** argv)
{
//___________________________________________________________________//
//                                                                   //

100 101 102 103 104 105
	SConfiguration l_oConfiguration;
	if(!parse_arguments(argc, argv, l_oConfiguration))
	{
		cout << "Syntax : " << argv[0] << " [ switches ]\n";
		cout << "Possible switches :\n";
		cout << "  --config filename       : path to config file\n";
106
		cout << "  --define token value    : specify configuration token with a given value\n";
107 108 109 110
		cout << "  --help                  : displays this help message and exits\n";
		cout << "  --kernel filename       : path to openvibe kernel library\n";
		return -1;
	}
Jozef Legeny's avatar
Jozef Legeny committed
111

112 113 114 115 116 117 118
#if defined(TARGET_OS_Windows)
	HANDLE l_oProcess = GetCurrentProcess();

	// Some sources claim this is needed for accurate timing. Microsoft disagrees, so we do not use it. You can try, or try google. 
	//SetThreadAffinityMask(hProcess, threadMask);

	// Set the clock interval to 1ms (default on Win7: 15ms). This is needed to get under 15ms accurate sleeps,
119 120 121
	// and improves the precision of non-QPC clocks. Note that since boost 1.58, the sleeps no longer seem
	// to be 1ms accurate on Windows (as they seemed to be on 1.55), and sleep can oversleep even 10ms even with 
	// timeBeginPeriod(1) called. @todo in the future, make sure nothing relies on sleep accuracy in openvibe
122 123 124 125 126 127 128 129 130 131 132
	timeBeginPeriod(1); 

	// Since AS is just sleeping when its not acquiring, a high priority should not be a problem. 
	// As a result of these calls, the server should have a 'normal' priority INSIDE the 'realtime' priority class.
	// However, unless you run AS with admin priviledges, Windows probably will truncate these priorities lower.
	// n.b. For correct timing, it may be preferable to set the priority here globally and not mess with it in the drivers;
	// any child threads should inherit this automagically.
	SetPriorityClass(l_oProcess, REALTIME_PRIORITY_CLASS);		// The highest priority class
	SetThreadPriority(l_oProcess, THREAD_PRIORITY_NORMAL);		// Even higher options: THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL
#endif

Jozef Legeny's avatar
Jozef Legeny committed
133 134 135 136 137 138 139 140 141
	CKernelLoader l_oKernelLoader;

	cout<<"[  INF  ] Created kernel loader, trying to load kernel module"<<endl;
	CString l_sError;
#if defined TARGET_OS_Windows
	CString l_sKernelFile = OpenViBE::Directories::getLibDir() + "/openvibe-kernel.dll";
#else
	CString l_sKernelFile = OpenViBE::Directories::getLibDir() + "/libopenvibe-kernel.so";
#endif
142 143 144 145
	if(l_oConfiguration.m_oFlag.count("kernel")) 
	{
		l_sKernelFile = CString(l_oConfiguration.m_oFlag["kernel"].c_str());
	}
Jozef Legeny's avatar
Jozef Legeny committed
146 147
	if(!l_oKernelLoader.load(l_sKernelFile, &l_sError))
	{
148
		cout<<"[ FAILED ] Error loading kernel from [" << l_sKernelFile << "]: " << l_sError << "\n";
Jozef Legeny's avatar
Jozef Legeny committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	}
	else
	{
		cout<<"[  INF  ] Kernel module loaded, trying to get kernel descriptor"<<endl;
		IKernelDesc* l_pKernelDesc=NULL;
		IKernelContext* l_pKernelContext=NULL;
		l_oKernelLoader.initialize();
		l_oKernelLoader.getKernelDesc(l_pKernelDesc);
		if(!l_pKernelDesc)
		{
			cout<<"[ FAILED ] No kernel descriptor"<<endl;
		}
		else
		{
			cout<<"[  INF  ] Got kernel descriptor, trying to create kernel"<<endl;
164 165 166 167 168 169 170 171 172


			CString l_sConfigFile = CString(OpenViBE::Directories::getDataDir() + "/kernel/openvibe.conf");
			if(l_oConfiguration.m_oFlag.count("config")) 
			{
				l_sConfigFile = CString(l_oConfiguration.m_oFlag["config"].c_str());
			}

			l_pKernelContext=l_pKernelDesc->createKernel("acquisition-server", l_sConfigFile);
Jozef Legeny's avatar
Jozef Legeny committed
173 174 175 176 177 178
			if(!l_pKernelContext)
			{
				cout<<"[ FAILED ] No kernel created by kernel descriptor"<<endl;
			}
			else
			{
179 180 181
				// @FIXME CERT what is the correct initialization convention? The legacy style from toolkit crashes.
				// OpenViBEToolkit::initialize(*l_pKernelContext);
				l_pKernelContext->initialize();
Jozef Legeny's avatar
Jozef Legeny committed
182 183 184

				IConfigurationManager& l_rConfigurationManager=l_pKernelContext->getConfigurationManager();

185 186 187 188 189 190
				// @FIXME CERT silent fail if missing file is provided
				l_rConfigurationManager.addConfigurationFromFile(l_rConfigurationManager.expand("${Path_Data}/applications/acquisition-server/acquisition-server-defaults.conf"));

				// User configuration mods
				l_rConfigurationManager.addConfigurationFromFile(l_rConfigurationManager.expand("${Path_UserData}/openvibe-acquisition-server.conf"));

191
				l_pKernelContext->getPluginManager().addPluginsFromFiles(l_rConfigurationManager.expand("${AcquisitionServer_Plugins}"));
Jozef Legeny's avatar
Jozef Legeny committed
192

193 194 195 196 197 198 199 200 201
				std::map<std::string, std::string>::const_iterator itr;
				for(itr=l_oConfiguration.m_oTokenMap.begin();
					itr!=l_oConfiguration.m_oTokenMap.end();
					itr++)
				{
					l_pKernelContext->getLogManager() << LogLevel_Trace << "Adding command line configuration token [" << (*itr).first.c_str() << " = " << (*itr).second.c_str() << "]\n";
					l_rConfigurationManager.addOrReplaceConfigurationToken((*itr).first.c_str(), (*itr).second.c_str());
				}

202 203 204 205 206 207 208 209 210 211
				if(!gtk_init_check(&argc, &argv))
				{
					l_pKernelContext->getLogManager() << LogLevel_Error << "Unable to initialize GTK. Possibly the display could not be opened. Exiting.\n";
					
					OpenViBEToolkit::uninitialize(*l_pKernelContext);
					l_pKernelDesc->releaseKernel(l_pKernelContext);

					l_oKernelLoader.uninitialize();
					l_oKernelLoader.unload();

212 213 214 215
#if defined(TARGET_OS_Windows)
					timeEndPeriod(1);
#endif

216 217
					return -2;
				}
Jozef Legeny's avatar
Jozef Legeny committed
218

219
				// gtk_rc_parse(OpenViBE::Directories::getDataDir() + "/applications/designer/interface.gtkrc");
Jozef Legeny's avatar
Jozef Legeny committed
220

221 222 223 224 225 226 227 228 229
#ifdef TARGET_OS_Linux
				// Replace the gtk signal handlers with the default ones. As a result, 
				// the following exits on terminating signals won't be graceful, 
				// but its better than not exiting at all (gtk default on Linux apparently)
				signal(SIGHUP, SIG_DFL);
				signal(SIGINT, SIG_DFL);
				signal(SIGQUIT, SIG_DFL);
#endif

Jozef Legeny's avatar
Jozef Legeny committed
230 231 232 233 234 235 236 237 238 239 240
#if 0 // This is not needed in the acquisition server
				if(l_rConfigurationManager.expandAsBoolean("${Kernel_3DVisualisationEnabled}"))
				{
					l_pKernelContext->getVisualisationManager().initialize3DContext();
				}
#endif

				{
					// If this is encapsulated by gdk_threads_enter() and gdk_threads_exit(), m_pThread->join() can hang when gtk_main() returns before destructor of app has been called.
					OpenViBEAcquisitionServer::CAcquisitionServerGUI app(*l_pKernelContext);

241 242


Jozef Legeny's avatar
Jozef Legeny committed
243 244
					try
					{
245
						gtk_main();	
Jozef Legeny's avatar
Jozef Legeny committed
246 247 248 249 250
					}
					catch(...)
					{
						l_pKernelContext->getLogManager() << LogLevel_Fatal << "Catched top level exception\n";
					}
251 252


Jozef Legeny's avatar
Jozef Legeny committed
253 254 255 256 257 258 259 260 261 262 263 264
				}

				cout<<"[  INF  ] Application terminated, releasing allocated objects"<<endl;

				OpenViBEToolkit::uninitialize(*l_pKernelContext);

				l_pKernelDesc->releaseKernel(l_pKernelContext);
			}
		}
		l_oKernelLoader.uninitialize();
		l_oKernelLoader.unload();
	}
265 266 267 268
			
#if defined(TARGET_OS_Windows)
	timeEndPeriod(1);
#endif
Jozef Legeny's avatar
Jozef Legeny committed
269 270 271

	return 0;
}