Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members

ArchiveManager.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   SpikeStream Application                                               *
00003  *   Copyright (C) 2007 by David Gamez                                     *
00004  *   david@davidgamez.eu                                                   *
00005  *   Version 0.1                                                           *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 
00023 //SpikeStream includes
00024 #include "ArchiveManager.h"
00025 #include "DBInterface.h"
00026 #include "Debug.h"
00027 #include "Utilities.h"
00028 #include "SpikeStreamMainWindow.h"
00029 
00030 //Qt includes
00031 #include <qwidget.h>
00032 
00033 //Other includes
00034 #include <mysql++.h>
00035 using namespace mysqlpp;
00036 
00037 
00038 //Declare and initialise static variables
00039 bool ArchiveManager::archiveRunning = false;
00040 
00041 
00042 /*! Constructor. */
00043 ArchiveManager::ArchiveManager(DBInterface *archDBInter, QWidget* archiveWidget){
00044         //Store references
00045         archiveDBInterface = archDBInter;
00046 
00047         //Set up a short version of spike stream application reference
00048         spikeStrApp = SpikeStreamMainWindow::spikeStreamApplication;
00049         
00050         //Initialise variables
00051         archiveLoaded = false;
00052 
00053         //Set up the xml handler and reader
00054         nwDataXmlHandler = new NetworkDataXmlHandler();
00055         xmlReader.setContentHandler(nwDataXmlHandler);
00056         xmlReader.setErrorHandler(nwDataXmlHandler);
00057         connect ( nwDataXmlHandler, SIGNAL(spikeCountChanged(unsigned int)), archiveWidget, SLOT(setSpikeCount(unsigned int)));
00058         connect ( nwDataXmlHandler, SIGNAL(spikeTotalChanged(unsigned int)), archiveWidget, SLOT(setSpikeTotal(unsigned int)));
00059         connect ( nwDataXmlHandler, SIGNAL(statisticsChanged()), archiveWidget, SLOT(updateStatisticsTable()));
00060 
00061         /* Set up the database using a new connection.*/
00062         dbConnection = archiveDBInterface->getNewConnection();
00063         archiveQuery = new Query(dbConnection->query());
00064 
00065         //Initialise the variables that will be used in the run method
00066         updateInterval_msec = 0;
00067         updateTime = QTime::currentTime();
00068         networkDataString = "";
00069         elapsedTime_msec = 0;
00070         timeStep = 0;
00071 
00072         //Set stop and step to false
00073         stop = false;
00074         step = false;
00075 }
00076 
00077 
00078 /*! Destructor. */
00079 ArchiveManager::~ArchiveManager(){
00080         #ifdef MEMORY_DEBUG
00081                 cout<<"DESTROYING ARCHIVE MANAGER"<<endl;
00082         #endif//MEMORY_DEBUG
00083 
00084         //Close network connection
00085         dbConnection->close();
00086 
00087         //Delete memory on the heap
00088         delete nwDataXmlHandler;
00089         delete archiveQuery;
00090 }
00091 
00092 
00093 //---------------------------------------------------------------------
00094 //-------------------------- PUBLIC METHODS ---------------------------
00095 //---------------------------------------------------------------------
00096 
00097 /*! Passes the new statistics on to the network data xml handler. */
00098 void ArchiveManager::addArchiveStatistics(ArchiveStatisticsHolder* newArchStat){
00099         nwDataXmlHandler->addArchiveStatistics(newArchStat);
00100 }
00101 
00102 
00103 /*! Returns true if archive is loaded. */
00104 bool ArchiveManager::archiveIsLoaded(){
00105         return archiveLoaded;
00106 }
00107 
00108 
00109 /*! Deletes the archive statistics from the network data xml handler
00110         using the statistic's id. */
00111 void ArchiveManager::deleteArchiveStatistics(unsigned int statID){
00112         nwDataXmlHandler->deleteArchiveStatistics(statID);
00113 }
00114 
00115 
00116 /*! Fast forwards archive by csetting the update interval very small. */
00117 bool ArchiveManager::fastForwardArchive(){
00118         if(archError){
00119                 SpikeStreamMainWindow::spikeStreamApplication->lock();
00120                 emit archiveError(QString("Archive has an error and cannot be fast forwarded."));
00121                 SpikeStreamMainWindow::spikeStreamApplication->unlock();
00122                 return false;
00123         }
00124 
00125         if(archiveLoaded){//Check to see if an archive is loaded
00126                 updateInterval_msec = 5;
00127                 stop = false;
00128                 if(!archiveRunning)
00129                         start();//Start the thread running if it is not running already
00130         }
00131         return true;
00132 }
00133 
00134 
00135 /*! Used when deleting an archive. This interferes with the resUse of the
00136         archiveManager, which has to be deleted and reinitialised after the deletion
00137         of the archive is complete. */
00138 void ArchiveManager::freezeArchive(){
00139         if(archiveLoaded){
00140                 //Delete archive results
00141                 delete archiveResults;
00142                 archiveResults = NULL;
00143         }
00144 }
00145 
00146 
00147 /*! Used to display the start date time of the currently loaded archive. */
00148 QString ArchiveManager::getSimulationStartDateTime(){
00149         return archiveStartDateTime;
00150 }
00151 
00152 
00153 /*! Returns true if the archive is running. */
00154 bool ArchiveManager::isRunning(){
00155         return archiveRunning;
00156 }
00157 
00158 
00159 /*! Load an archive ready for playing back.
00160         Exception handling for this operation is carried out by ArchiveWidget. */
00161 void ArchiveManager::loadArchive(QString startDateTime){
00162         //Store startDateTime to enable rewind
00163         archiveStartDateTime = startDateTime;
00164 
00165         //Reset statistics in xml handler       
00166         nwDataXmlHandler->resetStatistics();
00167 
00168         //Do any steps necessary to clean up previous archive
00169         if(archiveLoaded){
00170                 unloadArchive();
00171         }
00172 
00173         //Set up the query and the results that will be used to stream from database
00174         archiveDBInterface->checkDatabaseConnection(dbConnection);
00175         archiveQuery->reset();
00176         (*archiveQuery)<<"SELECT TimeStep, FiringNeurons FROM NetworkData WHERE SimulationStartTime = UNIX_TIMESTAMP(\""<<startDateTime<<"\") ORDER BY TimeStep";
00177         archiveResults = new ResUse(archiveQuery->use());//ResUse is much more efficient for large queries
00178 
00179         //Reset errors
00180         archError = false;
00181 
00182         //Everything ok up to this point
00183         archiveLoaded = true;
00184 }
00185 
00186 
00187 /*! Plays back archive. */
00188 bool ArchiveManager::playArchive(){
00189         if(archError){
00190                 SpikeStreamMainWindow::spikeStreamApplication->lock();
00191                 emit archiveError(QString("Archive has an error and cannot be played."));
00192                 SpikeStreamMainWindow::spikeStreamApplication->unlock();
00193                 return false;
00194         }
00195 
00196         if(archiveLoaded){//Check to see if an archive is loaded
00197                 updateInterval_msec = originalUpdateInterval_msec;
00198                 stop = false;
00199                 if(!archiveRunning)
00200                         start();//Start the thread running
00201         }
00202         return true;
00203 }
00204 
00205 
00206 /*! Rewinds archive to the beginning. */
00207 bool ArchiveManager::rewindArchive(){
00208         if(archError){
00209                 SpikeStreamMainWindow::spikeStreamApplication->lock();
00210                 emit archiveError(QString("Archive has an error and cannot be rewound."));
00211                 SpikeStreamMainWindow::spikeStreamApplication->unlock();
00212                 return false;
00213         }
00214 
00215         //Stop run method
00216         stop = true;
00217 
00218         //Reload current archive
00219         loadArchive(archiveStartDateTime);
00220 
00221         return true;
00222 }
00223 
00224 
00225 /*! Sets the update interval based on the frame rate. */
00226 void ArchiveManager::setFrameRate(double rate){
00227         //Set the update interval to the duration of each frame in miliseconds
00228         originalUpdateInterval_msec = (int) (1000.0 / rate);
00229         updateInterval_msec = originalUpdateInterval_msec;
00230 }
00231 
00232 
00233 /*! Sets the network monitors so that archived spike data can be passed to them. */
00234 void ArchiveManager::setNetworkMonitors(map<unsigned int, NetworkMonitor*> nwMonMap){
00235         networkMonitorMap = nwMonMap;
00236         nwDataXmlHandler->setNetworkMonitors(nwMonMap);
00237 }
00238 
00239 
00240 /*! Advances the archive playback by 1 step. Playback is automatically stopped
00241         after the step. */
00242 bool ArchiveManager::stepArchive(){
00243         if(archError){
00244                 SpikeStreamMainWindow::spikeStreamApplication->lock();
00245                 emit archiveError(QString("Archive has an error and cannot be stepped."));
00246                 SpikeStreamMainWindow::spikeStreamApplication->unlock();
00247                 return false;
00248         }
00249 
00250         if(archiveLoaded){//Check to see if an archive is loaded
00251                 stop = false;
00252                 step = true;
00253                 updateInterval_msec = 0;//Set update interval to 0 to get a faster response to the step
00254                 if(!archiveRunning)
00255                         start();//Start the thread running if it is not running already
00256         }
00257         return true;
00258 }
00259 
00260 
00261 /*! Stops archive playback. */
00262 bool ArchiveManager::stopArchive(){
00263         stop = true;
00264 
00265         #ifdef ARCHIVE_TRANSPORT_DEBUG
00266                 cout<<"ArchiveManager: setting stop to true"<<endl;
00267         #endif//ARCHIVE_TRANSPORT_DEBUG
00268 
00269         return true;
00270 }
00271 
00272 
00273 /*! Used when deleting an archive. This interferes with the resUse of the
00274         archiveManager, which has to be deleted and reinitialised after the deletion
00275         of the archive is complete. */
00276 void ArchiveManager::unfreezeArchive(){
00277         //Set up the query and the results that will be used to stream from database
00278         archiveDBInterface->checkDatabaseConnection(dbConnection);
00279         archiveQuery->reset();
00280         (*archiveQuery)<<"SELECT TimeStep, FiringNeurons FROM NetworkData WHERE SimulationStartTime = UNIX_TIMESTAMP(\""<<archiveStartDateTime<<"\") AND TimeStep >= "<<timeStep<<" ORDER BY TimeStep";
00281         archiveResults = new ResUse(archiveQuery->use());//ResUse is much more efficient for large queries
00282 }
00283 
00284 
00285 /*! Frees up query object so another resUse can access it. */
00286 bool ArchiveManager::unloadArchive(){
00287         if(archiveLoaded){
00288                 delete archiveResults;
00289                 archiveResults = NULL;
00290                 archiveLoaded = false;
00291         }
00292         return true;
00293 }
00294 
00295 
00296 //------------------------------------------------------------------------------
00297 //----------------- PROTECTED METHODS INHERITED FROM QTHREAD -------------------
00298 //------------------------------------------------------------------------------
00299 
00300 /*! Thread run method is used when playing back a simulation. */
00301 void ArchiveManager::run(){
00302         #ifdef ARCHIVE_TRANSPORT_DEBUG
00303                 cout<<"ArchiveManager: Start run"<<endl;
00304         #endif//ARCHIVE_TRANSPORT_DEBUG
00305         
00306         //Record that archive is running
00307         archiveRunning = true;
00308 
00309         //Declare the row that will be used to get the data from the results
00310         Row archiveRow;
00311 
00312         while(!stop){
00313                 try{
00314                         //Get XML data for frame
00315                         archiveRow = archiveResults->fetch_row();
00316 
00317                         //Read in time step
00318                         timeStep = Utilities::getUInt((std::string) archiveRow["TimeStep"]);
00319                         setTimeStep(timeStep);
00320 
00321                         //Read in xml file
00322                         networkDataString = (std::string) archiveRow["FiringNeurons"];
00323                         xmlInput.setData(networkDataString);
00324 
00325                         /* Check to see if enough time has elapsed and 
00326                                 sleep thread if not. */
00327                         elapsedTime_msec = updateTime.msecsTo(QTime::currentTime());
00328                         if(elapsedTime_msec < updateInterval_msec){
00329                                 #ifdef ARCHIVE_TRANSPORT_DEBUG
00330                                         cout<<"ArchiveManager: Going to sleep"<<endl;
00331                                 #endif//ARCHIVE_TRANSPORT_DEBUG
00332 
00333                                 //Sleep for remaning time
00334                                 usleep(1000 * (updateInterval_msec - elapsedTime_msec));
00335                         }
00336 
00337                         //Start xml parser: the XML handler will update the networkMonitors
00338                         #ifdef ARCHIVE_TRANSPORT_DEBUG
00339                                 cout<<"ArchiveManager: Parse data xml"<<endl;
00340                         #endif//ARCHIVE_TRANSPORT_DEBUG
00341 
00342                         xmlReader.parse(xmlInput);
00343                         if(nwDataXmlHandler->getParseError()){
00344                                 cerr<<"ArchiveWidget: ERROR OCCURRED DURING PARSING \""<<nwDataXmlHandler->getParseErrorString()<<"\""<<endl;
00345                                 QString archiveErrorString = "Error encountered whilst parsing XML Network Data: \"";
00346                                 archiveErrorString += nwDataXmlHandler->getParseErrorString();
00347                                 archiveErrorString += "\"";
00348                                 stop = true;//Stop the archive playing after the exception
00349                                 archError = true;//Don't want to try playing this archive again
00350                                 SpikeStreamMainWindow::spikeStreamApplication->lock();
00351                                 emit archiveError(archiveErrorString);
00352                                 SpikeStreamMainWindow::spikeStreamApplication->unlock();
00353                         }
00354 
00355                         //Record time at which this 'frame' was sent
00356                         updateTime = QTime::currentTime();
00357 
00358                         //In step mode set stop to true 
00359                         if(step){
00360                                 stop = true;
00361                                 step = false;
00362                                 updateInterval_msec = originalUpdateInterval_msec;//Restore the update interval
00363                         }
00364                 }
00365                 catch (const EndOfResults& er) {//EndOfResults exception thrown when fetch row no longer returns anything
00366                         #ifdef ARCHIVE_TRANSPORT_DEBUG
00367                                 cout<<"ArchiveManager: End of archive. Stopping"<<endl;
00368                         #endif//ARCHIVE_TRANSPORT_DEBUG
00369                         SpikeStreamMainWindow::spikeStreamApplication->lock();
00370                         emit stopped();
00371                         SpikeStreamMainWindow::spikeStreamApplication->unlock();
00372                 }
00373                 catch (const Exception& er){//Catch any other errors
00374                         cerr<<"ArchiveWidget: EXCEPTION \""<<er.what()<<"\""<<endl;
00375                         QString archiveErrorString = "Exception thrown when playing archive: \"";
00376                         archiveErrorString += er.what();
00377                         archiveErrorString += "\"";
00378                         stop = true;//Stop the archive playing after the exception
00379                         archError = true;
00380                         SpikeStreamMainWindow::spikeStreamApplication->lock();
00381                         emit archiveError(archiveErrorString);
00382                         SpikeStreamMainWindow::spikeStreamApplication->unlock();
00383                 }
00384                 catch (const std::exception& er) {// Catch-all for any std exceptions
00385                         cerr<<"ArchiveWidget: EXCEPTION \""<<er.what()<<"\""<<endl;
00386                         QString archiveErrorString = "Exception thrown when playing archive: \"";
00387                         archiveErrorString += er.what();
00388                         archiveErrorString += "\"";
00389                         stop = true;//Stop the archive playing after the exception
00390                         archError = true;
00391                         SpikeStreamMainWindow::spikeStreamApplication->lock();
00392                         emit archiveError(archiveErrorString);
00393                         SpikeStreamMainWindow::spikeStreamApplication->unlock();
00394         }
00395         }
00396         //Have exited the main while loop
00397         archiveRunning = false;
00398 
00399         #ifdef ARCHIVE_TRANSPORT_DEBUG
00400                 cout<<"ArchiveManager: Stop run"<<endl;
00401         #endif//ARCHIVE_TRANSPORT_DEBUG
00402 }
00403 
00404 
00405 //---------------------------------------------------------------------
00406 //------------------------- PRIVATE METHODS ---------------------------
00407 //---------------------------------------------------------------------
00408 
00409 /*! Sets the time step in the network monitors. */
00410 void ArchiveManager::setTimeStep(unsigned int timeStep){
00411         for(map<unsigned int, NetworkMonitor*>::iterator iter = networkMonitorMap.begin(); iter != networkMonitorMap.end(); ++iter)
00412                 iter->second->setTimeStep(timeStep);
00413 }
00414 
00415 

Generated on Mon Sep 3 22:29:04 2007 for SpikeStream Application by  doxygen 1.4.4