TOBI SignalServer
0.1
|
00001 /* 00002 This file is part of the TOBI signal server. 00003 00004 The TOBI signal server is free software: you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation, either version 3 of the License, or 00007 (at your option) any later version. 00008 00009 The TOBI signal server is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with Foobar. If not, see <http://www.gnu.org/licenses/>. 00016 00017 Copyright 2010 Christian Breitwieser 00018 Contact: c.breitwieser@tugraz.at 00019 */ 00020 00025 //----------------------------------------------------------------------------- 00026 00027 // STL 00028 #include <iostream> 00029 00030 // Boost 00031 #include <boost/asio.hpp> 00032 #include <boost/thread/thread.hpp> 00033 #include <boost/exception/all.hpp> 00034 #include <boost/filesystem.hpp> 00035 00036 // local 00037 #include "version.h" 00038 #include "tia/tia_server.h" 00039 #include "config/xml_parser.h" 00040 #include "hardware/hw_access.h" 00041 #include "filereading/data_file_handler.h" 00042 00043 using namespace std; 00044 00045 using namespace tobiss; 00046 00047 const string DEFAULT_XML_CONFIG = "server_config.xml"; 00048 const string COMMENTS_XML_CONFIG = "server_config_comments.xml"; 00049 00050 const string XML_CONFIG_FILE_PARAM = "-f"; 00051 const string LIST_HARDWARE_PARAM = "-l"; 00052 const string NEW_TIA_PARAM = "-n"; 00053 00054 #ifndef WIN32 00055 const string DEFAULT_XML_CONFIG_HOME_SUBDIR = string("/tobi_sigserver_cfg/"); 00056 const string TEMPLATE_XML_CONFIG = string("/usr/share/signalserver/") + DEFAULT_XML_CONFIG; 00057 const string TEMPLATE_XML_CONFIG_COMMENTS = string("/usr/share/signalserver/") + COMMENTS_XML_CONFIG; 00058 #endif 00059 00060 class DataPacketReader 00061 { 00062 public: 00063 DataPacketReader(HWAccess& hw_access, TiAServer& server) : 00064 hw_access_(hw_access), 00065 server_(server), 00066 stop_reading_(false) 00067 { } 00068 00069 void stop() 00070 { 00071 stop_reading_ = true; 00072 } 00073 00074 void readPacket() 00075 { 00076 while (!stop_reading_) 00077 { 00078 DataPacket p = hw_access_.getDataPacket(); 00079 server_.sendDataPacket(p); 00080 } 00081 } 00082 00083 private: 00084 HWAccess& hw_access_; 00085 TiAServer& server_; 00086 bool stop_reading_; 00087 }; 00088 00089 //----------------------------------------------------------------------------- 00090 string getDefaultConfigFile () 00091 { 00092 string default_xml_config = DEFAULT_XML_CONFIG; 00093 #ifdef WIN32 00094 // do nothing here at the moment ;) 00095 return default_xml_config; 00096 #else 00097 default_xml_config = string (getenv("HOME")) + DEFAULT_XML_CONFIG_HOME_SUBDIR + default_xml_config; 00098 string comments_xml_config = string (getenv("HOME")) + DEFAULT_XML_CONFIG_HOME_SUBDIR + COMMENTS_XML_CONFIG; 00099 boost::filesystem::path default_config_path (default_xml_config); 00100 boost::filesystem::path comments_config_path (comments_xml_config); 00101 00102 boost::filesystem::path template_config_path (TEMPLATE_XML_CONFIG); 00103 boost::filesystem::path template_comments_config_path (TEMPLATE_XML_CONFIG_COMMENTS); 00104 00105 if (!boost::filesystem::exists (default_config_path)) 00106 { 00107 if (boost::filesystem::exists (template_config_path)) 00108 { 00109 boost::filesystem::create_directory (default_config_path.parent_path()); 00110 boost::filesystem::copy_file (template_config_path, default_config_path); 00111 } 00112 if (boost::filesystem::exists (TEMPLATE_XML_CONFIG_COMMENTS)) 00113 boost::filesystem::copy_file (template_comments_config_path, comments_config_path); 00114 00115 } 00116 return default_xml_config; 00117 #endif 00118 } 00119 00120 00121 //----------------------------------------------------------------------------- 00122 00123 void printVersion() 00124 { 00125 cout << endl; 00126 cout << "SignalServer -- Version: " << MAJOR_VERSION; 00127 cout << " (build " << BUILD_NUMBER << ")"; 00128 #ifndef WIN32 00129 cout << " -- " << BUILD_STR; 00130 #else 00131 cout << " -- " << __DATE__ << " " << __TIME__; 00132 #endif 00133 cout << endl << endl; 00134 cout << "Laboratory of Brain-Computer Interfaces" << endl; 00135 cout << "Graz University of Technology" << endl; 00136 cout << "http://bci.tugraz.at" << endl; 00137 } 00138 00139 //----------------------------------------------------------------------------- 00140 00141 void printPossibleHardware() 00142 { 00143 cout << "Possible hardware abrevations to be used with this signal server version:" << endl; 00144 vector<string> hw_names = HWAccess::getPossibleHardwareNames(); 00145 for(unsigned int n = 0; n < hw_names.size(); n++) 00146 cout << " * " << hw_names[n] << endl; 00147 } 00148 00149 //----------------------------------------------------------------------------- 00150 //----------------------------------------------------------------------------- 00151 00152 int main(int argc, const char* argv[]) 00153 { 00154 try 00155 { 00156 printVersion(); 00157 00158 string config_file; 00159 bool running = true; 00160 bool use_new_tia = false; 00161 00162 if(argc == 1) 00163 { 00164 config_file = getDefaultConfigFile (); 00165 cout << endl << " *** Loading default XML configuration file: " << config_file << endl << endl; 00166 } 00167 else if(argc == 2) 00168 { 00169 if(argv[1] == LIST_HARDWARE_PARAM) 00170 { 00171 printPossibleHardware(); 00172 return(0); 00173 } 00174 else if (argv[1] == NEW_TIA_PARAM) 00175 { 00176 use_new_tia = true; 00177 cout << endl << " *** Signal Server will start with TiA 1.0 ***" << endl; 00178 config_file = getDefaultConfigFile (); 00179 cout << endl << " *** Loading default XML configuration file: " << config_file << endl << endl; 00180 } 00181 else 00182 { 00183 cout << endl << " *** Loading XML configuration file: " << argv[1] << endl << endl; 00184 config_file = argv[1]; 00185 } 00186 } 00187 else if(argc == 3 && argv[1] == XML_CONFIG_FILE_PARAM) 00188 { 00189 cout << endl << " *** Loading XML configuration file: " << argv[2] << endl << endl; 00190 config_file = argv[2]; 00191 } 00192 else 00193 throw(std::invalid_argument(" ERROR -- Failure parsing input arguments!") ); 00194 00195 while(running) 00196 { 00197 XMLParser config(config_file); 00198 00199 00200 boost::asio::io_service io_service; 00201 00202 TiAServer server(io_service, use_new_tia); 00203 00204 // DataFileHandler data_file_handler(io_service, config.getFileReaderMap()); 00205 00206 HWAccess hw_access(io_service, config); 00207 DataPacketReader reader(hw_access, server); 00208 boost::thread* io_thread_ptr_1 = 0; 00209 boost::thread* io_thread_ptr_2 = 0; 00210 boost::thread* data_reader_thread_ptr = 0; 00211 00212 if(config.usesDataFile()) 00213 { 00214 // get DataPackets from FileReader and give it to the networking part 00215 } 00216 else 00217 { 00218 // TODO: find a better way to pass this information to the server 00219 server.setMasterBlocksize(hw_access.getMastersBlocksize()); 00220 server.setMasterSamplingRate(hw_access.getMastersSamplingRate()); 00221 server.setAcquiredSignalTypes(hw_access.getAcquiredSignalTypes()); 00222 server.setBlockSizesPerSignalType(hw_access.getBlockSizesPerSignalType()); 00223 server.setSamplingRatePerSignalType(hw_access.getSamplingRatePerSignalType()); 00224 server.setChannelNames(hw_access.getChannelNames()); 00225 00226 server.initialize(config.parseSubject(),config.parseServerSettings()); 00227 hw_access.startDataAcquisition(); 00228 00229 io_thread_ptr_1 = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service)); 00230 io_thread_ptr_2 = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service)); 00231 data_reader_thread_ptr = new boost::thread(boost::bind(&DataPacketReader::readPacket, &reader)); 00232 00233 #ifdef WIN32 00234 SetPriorityClass(io_thread_ptr_1->native_handle(), REALTIME_PRIORITY_CLASS); 00235 SetThreadPriority(io_thread_ptr_1->native_handle(), THREAD_PRIORITY_TIME_CRITICAL ); 00236 SetPriorityClass(io_thread_ptr_2->native_handle(), REALTIME_PRIORITY_CLASS); 00237 SetThreadPriority(io_thread_ptr_2->native_handle(), THREAD_PRIORITY_TIME_CRITICAL ); 00238 00239 SetPriorityClass(data_reader_thread_ptr->native_handle(), REALTIME_PRIORITY_CLASS); 00240 SetThreadPriority(data_reader_thread_ptr->native_handle(), THREAD_PRIORITY_TIME_CRITICAL ); 00241 #endif 00242 } 00243 00244 #ifdef WIN32 00245 SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); 00246 #endif 00247 00248 string str; 00249 cout << endl << ">>"; 00250 00251 while(cin >> str) 00252 { 00253 if(str == "q" || str == "quit" || str == "exit") 00254 { 00255 running = false; 00256 break; 00257 } 00258 else if(str == "r") 00259 { 00260 break; 00261 } 00262 else if(str == "h" || str == "help") 00263 { 00264 cout << "q (quit) ... Quit the signalserver" << endl; 00265 cout << "r (restart) ... Restart the signalserver (WARNING: malfunction with certain amplifiers possible)" << endl; 00266 cout << "l (list) ... List possible hardware devices" << endl; 00267 cout << "h (help) ... Print this help" << endl; 00268 cout << endl << ">>"; 00269 } 00270 else if(str == "l" || str == "list") 00271 { 00272 printPossibleHardware(); 00273 cout << endl << ">>"; 00274 } 00275 else 00276 cout << endl << ">>"; 00277 } 00278 00279 reader.stop(); 00280 io_service.stop(); 00281 hw_access.stopDataAcquisition(); 00282 if(io_thread_ptr_1) 00283 { 00284 io_thread_ptr_1->join();; 00285 delete io_thread_ptr_1; 00286 io_thread_ptr_1 = 0; 00287 } 00288 if(io_thread_ptr_2) 00289 { 00290 io_thread_ptr_2->join(); 00291 delete io_thread_ptr_2; 00292 io_thread_ptr_2 = 0; 00293 } 00294 if(data_reader_thread_ptr) 00295 { 00296 data_reader_thread_ptr->join(); 00297 delete data_reader_thread_ptr; 00298 } 00299 00300 if(running) 00301 { 00302 cout << endl; 00303 cout << " ... Restarting and reloading SignalServer!" << endl; 00304 cout << endl; 00305 boost::this_thread::sleep(boost::posix_time::seconds(1)); 00306 } 00307 } 00308 } 00309 catch(ticpp::Exception& ex) 00310 { 00311 cerr << endl << " ***** TICPP Exception caught! *****" << endl; 00312 cerr << " --> " << ex.what() << endl << endl; 00313 std::cin.peek(); 00314 } 00315 catch(std::invalid_argument& e) 00316 { 00317 cerr << endl << " ***** STL Exception -- Invalid argument -- caught! *****" << endl; 00318 cerr << " --> " << e.what() << endl << endl; 00319 std::cin.peek(); 00320 } 00321 catch(std::length_error& e) 00322 { 00323 cerr << endl << " ***** STL Exception -- Length error -- caught! *****" << endl; 00324 cerr << " --> " << e.what() << endl << endl; 00325 std::cin.peek(); 00326 } 00327 catch(std::logic_error& e) 00328 { 00329 cerr << endl << " ***** STL Exception -- Logic error -- caught! *****" << endl; 00330 cerr << " --> " << e.what() << endl << endl; 00331 std::cin.peek(); 00332 } 00333 catch(std::range_error& e) 00334 { 00335 cerr << endl << " ***** STL Exception -- Range error -- caught! *****" << endl; 00336 cerr << " --> " << e.what() << endl << endl; 00337 std::cin.peek(); 00338 } 00339 catch(std::runtime_error& e) 00340 { 00341 cerr << endl << " ***** STL Exception -- Runtime error -- caught! *****" << endl; 00342 cerr << " --> " << e.what() << endl << endl; 00343 std::cin.peek(); 00344 } 00345 catch(std::exception& e) 00346 { 00347 cerr << endl << " ***** STL Exception caught! *****" << endl; 00348 cerr << " --> " << e.what() << endl << endl; 00349 std::cin.peek(); 00350 } 00351 catch(boost::exception& e) 00352 { 00353 cerr << endl << " ***** Boost Exception caught! *****" << endl; 00354 cerr << " --> " << boost::diagnostic_information(e) << endl << endl; 00355 std::cin.peek(); 00356 } 00357 catch(...) 00358 { 00359 cerr << endl << " ***** Caught unknown exception! *****" << endl; 00360 std::cin.peek(); 00361 } 00362 00363 cerr.flush(); 00364 return(0); 00365 } 00366 00367 //-----------------------------------------------------------------------------