TOBI SignalServer  0.1
/home/breidi/Dropbox/signalserver/src/signalserver/signalserver.cpp
00001 /*
00002     This file is part of the TOBI SignalServer.
00003 
00004     Commercial Usage
00005     Licensees holding valid Graz University of Technology Commercial
00006     licenses may use this file in accordance with the Graz University
00007     of Technology Commercial License Agreement provided with the
00008     Software or, alternatively, in accordance with the terms contained in
00009     a written agreement between you and Graz University of Technology.
00010 
00011     --------------------------------------------------
00012 
00013     GNU General Public License Usage
00014     Alternatively, this file may be used under the terms of the GNU
00015     General Public License version 3.0 as published by the Free Software
00016     Foundation and appearing in the file gpl.txt included in the
00017     packaging of this file.  Please review the following information to
00018     ensure the GNU General Public License version 3.0 requirements will be
00019     met: http://www.gnu.org/copyleft/gpl.html.
00020 
00021     In case of GNU General Public License Usage ,the TOBI SignalServer
00022     is distributed in the hope that it will be useful,
00023     but WITHOUT ANY WARRANTY; without even the implied warranty of
00024     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025     GNU General Public License for more details.
00026 
00027     You should have received a copy of the GNU General Public License
00028     along with the TOBI SignalServer. If not, see <http://www.gnu.org/licenses/>.
00029 
00030     Copyright 2010 Graz University of Technology
00031     Contact: SignalServer@tobi-project.org
00032 */
00033 
00034 #include "signalserver/signalserver.h"
00035 
00036 #include <fstream>
00037 #include <boost/date_time.hpp>
00038 #include <boost/filesystem.hpp>
00039 
00040 #include "tia/tia_server.h"
00041 #include "tia/data_packet_interface.h"
00042 #include "hardware/hw_access.h"
00043 #include "config/xml_parser.h"
00044 
00045 
00046 #include <tobiid/IDMessage.hpp>
00047 #include "TiDlib/tid_server.h"
00048 
00049 
00050 #include "libgdf/GDF/Writer.h"
00051 
00052 namespace tobiss
00053 {
00054 //-----------------------------------------------------------------------------
00055 
00056 SignalServer::SignalServer(XMLParser& config_parser, bool use_new_tia)
00057   : hw_access_(0), tia_server_(0), tia_io_service_thread_(0),hw_access_io_service_thread_(0),
00058     config_parser_(config_parser),
00059     stop_reading_(false), write_file_(false),
00060     master_blocksize_( 0 ),
00061     master_samplingrate_( 0 )
00062     #ifdef USE_TID_SERVER
00063       ,tid_server_(0),tid_io_service_thread_(0)
00064     #endif
00065     #ifdef USE_GDF_SAVER
00066       ,gdf_writer_(0)
00067     #endif
00068 {
00069   #ifdef DEBUG
00070     std::cout << BOOST_CURRENT_FUNCTION <<  std::endl;
00071   #endif
00072 
00073   tia_server_ = new tia::TiAServer(tia_io_service_, use_new_tia);
00074   hw_access_ = new HWAccess(hw_access_io_service_, config_parser_);
00075 
00076   master_blocksize_ =  hw_access_->getMastersBlocksize();
00077   master_samplingrate_ = hw_access_->getMastersSamplingRate();
00078 
00079   tia_server_->setMasterBlocksize( master_blocksize_ );
00080   tia_server_->setMasterSamplingRate( master_samplingrate_ );
00081   tia_server_->setAcquiredSignalTypes( hw_access_->getAcquiredSignalTypes() );
00082   tia_server_->setBlockSizesPerSignalType( hw_access_->getBlockSizesPerSignalType() );
00083 
00084   sampling_rate_per_sig_type_ = hw_access_->getSamplingRatePerSignalType();
00085   tia_server_->setSamplingRatePerSignalType(sampling_rate_per_sig_type_);
00086 
00087   channels_per_sig_type_ = hw_access_->getChannelNames();
00088   tia_server_->setChannelNames(channels_per_sig_type_);
00089 
00090   subject_info_ = config_parser_ .parseSubject();
00091   server_settings_ = config_parser_.parseServerSettings();
00092 
00093   tia_server_->initialize(subject_info_, server_settings_);
00094 
00095   packet_ = tia_server_->getEmptyDataPacket();
00096   packet_->reset();
00097 
00098   #ifdef USE_TID_SERVER
00099     tid_server_ = new TiD::TiDServer(tid_io_service_);
00100     tid_server_->bind ( boost::lexical_cast<unsigned int>(server_settings_[tia::Constants::ss_tid_port]));
00101     tid_server_->listen();
00102 
00103     tid_io_service_thread_ = new boost::thread(boost::bind(&boost::asio::io_service::run,
00104                                                            &tid_io_service_));
00105   #endif
00106 
00107 
00108   #ifdef USE_GDF_SAVER
00109     try
00110     {
00111       if(server_settings_[tia::Constants::ss_filetype] == "gdf")
00112       {
00113         gdf_writer_ = new gdf::Writer();
00114         initGdf();
00115         write_file_ = true;
00116       }
00117     }
00118     catch( std::exception &e )
00119     {
00120       std::cerr << "  -- Caught exception from GDF writer!"  << std::endl;
00121       throw;
00122     }
00123   #endif
00124 
00125   hw_access_->startDataAcquisition();
00126   hw_access_io_service_thread_ = new boost::thread(boost::bind(&boost::asio::io_service::run,
00127                                                                &hw_access_io_service_));
00128   tia_io_service_thread_ = new boost::thread(boost::bind(&boost::asio::io_service::run,
00129                                                                &tia_io_service_));
00130 
00131 #ifdef WIN32
00132   SetPriorityClass(tia_io_service_thread_->native_handle(), REALTIME_PRIORITY_CLASS);
00133   SetThreadPriority(tia_io_service_thread_->native_handle(), THREAD_PRIORITY_TIME_CRITICAL );
00134 
00135   SetPriorityClass(hw_access_io_service_thread_->native_handle(), REALTIME_PRIORITY_CLASS);
00136   SetThreadPriority(hw_access_io_service_thread_->native_handle(), THREAD_PRIORITY_TIME_CRITICAL );
00137 
00138   #ifdef USE_TID_SERVER
00139     SetPriorityClass(tid_io_service_thread_->native_handle(), REALTIME_PRIORITY_CLASS);
00140     SetThreadPriority(tid_io_service_thread_->native_handle(), THREAD_PRIORITY_TIME_CRITICAL );
00141   #endif
00142 
00143 #endif
00144 }
00145 
00146 //-----------------------------------------------------------------------------
00147 
00148 SignalServer::~SignalServer()
00149 {
00150   #ifdef DEBUG
00151     std::cout << BOOST_CURRENT_FUNCTION <<  std::endl;
00152   #endif
00153 
00154   stop();
00155 
00156   if(tia_io_service_thread_)
00157     delete(tia_io_service_thread_);
00158 
00159   if(tia_server_)
00160     delete(tia_server_);
00161 
00162 
00163   if(hw_access_io_service_thread_)
00164     delete(hw_access_io_service_thread_);
00165 
00166   if(hw_access_)
00167     delete(hw_access_);
00168 
00169 
00170   #ifdef USE_TID_SERVER
00171     if(tid_io_service_thread_)
00172       delete(tid_io_service_thread_);
00173 
00174     if(tid_server_)
00175       delete(tid_server_);
00176   #endif
00177 
00178   #ifdef USE_GDF_SAVER
00179     if(gdf_writer_)
00180     {
00181       gdf_writer_->close();
00182       delete gdf_writer_;
00183     }
00184   #endif
00185 }
00186 
00187 //-----------------------------------------------------------------------------
00188 
00189 void SignalServer::stop()
00190 {
00191   #ifdef DEBUG
00192     std::cout << BOOST_CURRENT_FUNCTION <<  std::endl;
00193   #endif
00194 
00195   stop_reading_ = true;
00196 
00197   hw_access_io_service_.stop();
00198   hw_access_io_service_thread_->interrupt();
00199   hw_access_io_service_thread_->join();
00200 
00201   tia_io_service_.stop();
00202   tia_io_service_thread_->interrupt();
00203   tia_io_service_thread_->join();
00204 
00205   #ifdef USE_TID_SERVER
00206     tid_io_service_.stop();
00207     tid_io_service_thread_->interrupt();
00208     tid_io_service_thread_->join();
00209   #endif
00210 
00211   hw_access_->stopDataAcquisition();
00212 }
00213 
00214 //-----------------------------------------------------------------------------
00215 
00216 void SignalServer::readPackets()
00217 {
00218   #ifdef DEBUG
00219     std::cout << BOOST_CURRENT_FUNCTION <<  std::endl;
00220   #endif
00221 
00222   boost::uint64_t sample_count = 0;
00223 
00224   while (!stop_reading_)
00225   {
00226     sample_count += master_blocksize_;
00227 
00228     hw_access_->fillDataPacket(packet_);
00229     tia_server_->sendDataPacket();
00230   }
00231 }
00232 
00233 //-----------------------------------------------------------------------------
00234 
00235 void SignalServer::fustyReadPackets()
00236 {
00237   #ifdef DEBUG
00238     std::cout << BOOST_CURRENT_FUNCTION <<  std::endl;
00239   #endif
00240 
00241   #ifdef USE_TID_SERVER
00242     std::vector<IDMessage> msgs;
00243     msgs.reserve(100);
00244     std::ofstream events_file;
00245   #endif
00246 
00247   boost::uint64_t sample_count = 0;
00248 
00249 
00250   while (!stop_reading_)
00251   {
00252     sample_count += master_blocksize_;
00253 
00254     hw_access_->fillDataPacket(packet_);
00255     tia_server_->sendDataPacket();
00256 
00257     #ifdef USE_TID_SERVER
00258     if(tid_server_->newMessagesAvailable())
00259       tid_server_->getLastMessages(msgs);
00260     #endif
00261 
00262     #ifdef USE_GDF_SAVER
00263     if(write_file_)
00264     {
00265       uint32_t nr_values = 0;
00266       uint32_t nr_blocks = 0;
00267       uint32_t nr_channels = 0;
00268       std::vector<double> v;
00269       uint32_t ch_start = 0;
00270 
00271       for(std::map<uint32_t, std::vector<std::string> >::iterator it(channels_per_sig_type_.begin());
00272         it != channels_per_sig_type_.end();  it++)
00273       {
00274         try
00275         {
00276           v = packet_->getSingleDataBlock(it->first);
00277           nr_values = packet_->getNrOfSamples(it->first);
00278           nr_channels = packet_->getNrOfChannels(it->first);
00279           nr_blocks = nr_values/nr_channels;
00280 
00281           for(uint32_t n = 0; n < nr_values/nr_blocks; n++)
00282             for(uint32_t m = 0; m < nr_blocks; m++)
00283             {
00284               gdf_writer_->addSamplePhys(ch_start + n, v[ (n*nr_blocks) + m]);
00285             }
00286         }
00287         catch( std::exception& e )
00288         {
00289           std::cerr << "  Caught exception from GDF writer: " << e.what() << std::endl;
00290           throw;
00291         }
00292         ch_start += it->second.size();
00293       }
00294 
00295       #ifdef USE_TID_SERVER
00296       for(unsigned int n = 0; n < msgs.size(); n++)
00297       {
00298         if(msgs[n].GetFamilyType() == IDMessage::FamilyBiosig)
00299         {
00300           if(msgs[n].GetBlockIdx() >0)
00301           {
00302             std::cout << "Current sample count: " << sample_count << std::endl;
00303             gdf_writer_->addEvent(msgs[n].GetBlockIdx()*master_blocksize_, msgs[n].GetEvent() );
00304           }
00305           else
00306           {
00307             gdf_writer_->addEvent(sample_count, msgs[n].GetEvent() );
00308             std::cout << "Used BlockNr: " << sample_count << std::endl;
00309           }
00310           msgs[n].Dump();
00311           std::string timestamp;
00312           msgs[n].absolute.Get(&timestamp);
00313           std::cout << " + Timestamp: " << timestamp << std::endl;
00314         }
00315         else
00316         {
00317           if(!events_file.is_open())
00318           {
00319             std::cerr << "Received a 'non-gdf' event -- saving into .txt file 'events_file.txt'." << std::endl;
00320             events_file.open("events_file.txt");
00321             boost::posix_time::ptime t(boost::posix_time::second_clock::local_time());
00322             events_file << std::endl << t << std::endl;
00323             events_file << "FamilyType:Family:Position:Event:Description:AbsTimestamp:RelTimeStamp" << std::endl;
00324           }
00325           msgs[n].Dump();
00326           events_file << msgs[n].GetFamilyType() << ":";
00327           events_file << msgs[n].GetFamily() << ":";
00328           events_file << msgs[n].GetBlockIdx()*master_blocksize_ << ":";
00329           events_file << msgs[n].GetEvent() << ":";
00330           events_file << msgs[n].GetDescription() << ":";
00331           events_file << "0" << ":";
00332           events_file << "0" << std::endl;
00333         }
00334       }
00335       #endif
00336     }
00337     #endif
00338 
00339     #ifdef USE_TID_SERVER
00340       if(msgs.size())
00341         msgs.clear();
00342     #endif
00343   }
00344 
00345   #ifdef USE_TID_SERVER
00346     if(!events_file.is_open())
00347       events_file.close();
00348   #endif
00349 
00350 }
00351 
00352 //-----------------------------------------------------------------------------
00353 #ifdef USE_GDF_SAVER
00354 void SignalServer::initGdf()
00355 {
00356   std::map<uint32_t, std::vector<std::string> >::iterator it(channels_per_sig_type_.begin());
00357 
00358   tia::Constants cst;
00359 
00360   for(uint32_t m = 0 ; it != channels_per_sig_type_.end(); it++, m++)
00361   {
00362     for(uint32_t n = 0; n < it->second.size(); n++)
00363     {
00364       int ind = gdf_writer_->getFirstFreeSignalIndex();
00365       gdf_writer_->createSignal(ind);
00366       gdf_writer_->getSignalHeader(ind).set_label( cst.getSignalName(it->first) + ":" + it->second[n] );
00367       gdf_writer_->getSignalHeader(ind).set_datatype( gdf::FLOAT32 );
00368       gdf_writer_->getSignalHeader(ind).set_samplerate(sampling_rate_per_sig_type_[m]);
00369       gdf_writer_->getSignalHeader(ind).set_digmin( -250000 );
00370       gdf_writer_->getSignalHeader(ind).set_digmax( 250000 );
00371       gdf_writer_->getSignalHeader(ind).set_physmin( -250000 );
00372       gdf_writer_->getSignalHeader(ind).set_physmax( 250000 );
00373     }
00374   }
00375 
00376   gdf_writer_->getHeaderAccess().setRecordDuration( 2* master_samplingrate_, 2*master_samplingrate_ );
00377 
00378   gdf_writer_->setEventMode( 1 );     // FIXME: 1 ... EventMode 1 (gdf)
00379   gdf_writer_->setEventSamplingRate( master_samplingrate_ );
00380 
00381   double systime = boost::numeric_cast<double>( time( NULL ) );
00382   double tmptime = ( systime/(3600.0*24.0) + 719529.0 ) * pow(2.0,32);
00383   gdf_writer_->getMainHeader( ).set_recording_start( boost::numeric_cast<gdf::uint64>(tmptime) );
00384 
00385   std::cout << "  ** Saving data to file: " << server_settings_[tia::Constants::ss_filename] << ".gdf" << std::endl;
00386 
00387   boost::filesystem::path p( server_settings_[tia::Constants::ss_filename] + ".gdf" );
00388 
00389   if(exists(p) && server_settings_[tia::Constants::ss_file_overwrite] == "1")
00390   {
00391     if(is_regular_file(p))
00392     {
00393       std::cout << "  **** WARNING **** Old file is overwritten now!" << std::endl;
00394       boost::filesystem3::remove(p);
00395     }
00396     else
00397       throw(std::invalid_argument( p.string() + "exists, but is not a regular file!"));
00398   }
00399 
00400   gdf_writer_->open( server_settings_[tia::Constants::ss_filename] + ".gdf" );
00401 }
00402 #endif
00403 
00404 //-----------------------------------------------------------------------------
00405 
00406 std::vector<std::string> SignalServer::getPossibleHardwareNames()
00407 {
00408   #ifdef DEBUG
00409     std::cout << "SignalServer: getPossibleHardwareNames" << std::endl;
00410   #endif
00411 
00412   return(HWAccess::getPossibleHardwareNames());
00413 }
00414 
00415 //-----------------------------------------------------------------------------
00416 
00417 }  // tobiss
00418 
 All Data Structures Files Functions Variables