Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

FileSystemDataSource.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_FileSystemDataSource_h_
00003 #define INCLUDED_FileSystemDataSource_h_
00004 
00005 #include "local/DataSource.h"
00006 #include "Shared/plist.h"
00007 #include "Shared/get_time.h"
00008 #include "IPC/Thread.h"
00009 #include <list>
00010 #include <iostream>
00011 
00012 class LoggedDataDriver;
00013 
00014 //! Manages the loading of a series of files from disk
00015 /*! Can handle an index file listing other data files and their timestamps,
00016  *  a directory holding a set of files, or a single explicit file. */
00017 class FileSystemDataSource : public virtual DataSource, public virtual plist::Dictionary, public virtual plist::PrimitiveListener {
00018 public:
00019   //! constructor
00020   FileSystemDataSource(LoggedDataDriver& p, const std::string& filter)
00021     : DataSource(), plist::Dictionary(), PrimitiveListener(), path(), filenameFilter(filter), loop(true), framerate(1000.f/(FrameTime*NumFrames)), verbose(0),
00022     poller(*this), files(), curfile(files.begin()),
00023     initialDelay(0), nextTime(0), indexed(true), freezeTime(), timeScale(NULL), parent(p), actualLoopTime(0), naturalLoopTime(0), lock(), registered(false)
00024   {
00025     setLoadSavePolicy(FIXED,SYNC);
00026     addEntry("Path",path,"If set, overrides the common LoggedData driver path.  In addition to directory or index file, can also be set to a single input data file.");
00027     addEntry("FileFilter",filenameFilter,"If Source is a directory or index file, only files matching the filter will be loaded from it.");
00028     addEntry("Loop",loop,"If true, restart file list at the beginning when the end is reached; otherwise just stop loading data");
00029     addEntry("Framerate",framerate,"The sensors updates per second which should be loaded.\nNote this is limited by the global Sensors.Framerate setting");
00030     addEntry("Verbose",verbose,"Controls how much feedback to give on the console regarding progress\n  0 - none\n  1 - report when messages are dropped\n  2 - also report when a message is sent\n  3 - also report when loop occurs\n  4 - also report when each message is preloaded");
00031   }
00032 
00033   //! destructor
00034   ~FileSystemDataSource();
00035   
00036   virtual unsigned int nextTimestamp();
00037   virtual const std::string& nextName();
00038   virtual bool advance();
00039   virtual void registerSource();
00040   virtual bool isRegistered() const { return registered; } //!< returns #registered
00041   virtual void deregisterSource();
00042   virtual void enteringRealtime(const plist::Primitive<double>& simTimeScale);
00043   virtual void leavingRealtime(bool /*isFullSpeed*/);
00044   
00045   //! sets the next frame to be sent (e.g. pass 0 to reset to the first frame)
00046   /*! prepares (pre-loads) @a numPreload frames from the new #curfile onward */
00047   virtual void setFrame(unsigned int f, unsigned int numPreload=2);
00048   
00049   //! increments #curfile to the next frame, preparing (pre-loads) @a numPreload frames from the new #curfile onward
00050   virtual void nextFrame(unsigned int numPreload=2);
00051   
00052   //! returns the total time taken to loop over the files
00053   /*! @param actual if false, will return the "natural" time of a loop, ignoring setLoopTime() effects */
00054   virtual double getLoopTime(bool actual=true) const { return actual ? actualLoopTime : naturalLoopTime; }
00055   virtual void setLoopTime(double t); //!< adds time to the final frame to increase total sequence time to @a t milliseconds
00056   
00057   virtual bool usingIndexFile() const { return indexed; } //!< returns #indexed
00058   
00059   //! empties #files
00060   void clearFiles();
00061   
00062   virtual void plistValueTouched(const plist::PrimitiveBase& pl);
00063   virtual void plistValueChanged(const plist::PrimitiveBase& pl);
00064   
00065   virtual void loadXML(xmlNode* node);
00066   
00067   //! returns the target path, either #path, or parent.path if #path is empty
00068   virtual const std::string& getUsedPath() const;
00069   
00070   //! call this to (re)load the list of available file names from disk
00071   /*! If @a clearCurrent is set, then the current file list will be cleared;
00072    *  otherwise, the loaded files will be appended to the current queue */
00073   virtual bool loadFileList(bool clearCurrent=true, bool reportMissing=true);
00074   
00075   //! The directory, data file, or index file from which to load via call to loadFileListFromDirectory(), loadSingleFile(), or loadFileListFromIndex()
00076   /*! A single file can be either a single data file (e.g. sensor or camera image), or an index file as output by VisionGUI, or in the format 'filename <tab> time', where 'filename' is an absolute path or relative to the directory containing the index file, and 'time' is in milliseconds, relative to the time at which the index file is loaded.\n In the future, this could also be network addresses for teleoperation and remote processing. */
00077   plist::Primitive<std::string> path;
00078   
00079   //! a regular expression (POSIX.2 extended format) to select which files to load from #path, if #path is a directory or index file
00080   plist::Primitive<std::string> filenameFilter;
00081   
00082   //! controls whether to restart #curfile at the beginning of #files when it reaches the end
00083   plist::Primitive<bool> loop;
00084   
00085   //! The sensors updates per second which should be loaded.  Note this is limited by the global Sensors.Framerate setting
00086   plist::Primitive<float> framerate;
00087   
00088   //! Controls how much feedback to give on the console regarding progress
00089   /*! 0 - none\n
00090    *  1 - report when messages are dropped\n
00091    *  2 - also report when a message is sent\n
00092    *  3 - also report when loop or end-of-log occurs\n
00093    *  4 - also report when each message is preloaded */
00094   plist::Primitive<int> verbose;
00095   
00096 protected:
00097   static const unsigned int MAX_LOAD=4000; //!< maximum number of data elements to try to keep 'active'.  If there's more than this in #files, we'll only load one at time, and immediately release it afterward
00098   struct FileInfo;
00099   typedef std::list<FileInfo*> files_t; //!< type of #files, the list of files to load
00100   
00101   struct DataThread : public Thread {
00102     DataThread(FileSystemDataSource& p) : parent(p) {}
00103     virtual void* run();
00104     FileSystemDataSource& parent;
00105   } poller;
00106   
00107   //! Gives the data referenced by curfile to the simulator
00108   virtual bool sendData()=0;
00109   
00110   virtual void doFreeze();
00111   virtual void doUnfreeze();
00112   virtual void resetPoller();
00113   
00114   //! load a single file
00115   virtual void loadSingleFile(const std::string& file);
00116   //! load a list of files from a directory specified by #path
00117   virtual void loadFileListFromDirectory();
00118   //! load a list of files from an index file specified by #path
00119   /*! This supports either the format produced by VisionGUI, or a simplier '<code>filename [<tab> time]\\n</code>' format,
00120    *  where if @c time is unspecified, the frame's time is incremented by the #framerate from the previously listed file.
00121    *  Filenames should either be either absolute paths or relative to the directory which contains the index file.*/
00122   virtual bool loadFileListFromIndex();
00123   
00124   //! adds up the lifetime of all #files, plus #initialDelay
00125   virtual double calcLoopTime() const;
00126   
00127   //! stores basic information regarding each file in the queue, including routines for loading to and from disk
00128   struct FileInfo {
00129     //! default constructor
00130     FileInfo() : filename(), lifetime(0), data(NULL), size(0), refcount(NULL), prepared(false) { }
00131     //! basic constructor, provide name and lifetime, data and size are left empty until later prepare() is called
00132     FileInfo(const std::string& name, double time) : filename(name), lifetime(time), data(NULL), size(0), refcount(NULL), prepared(false) { }
00133     //! copy constructor, adds reference to the source's data (shallow copy)
00134     FileInfo(const FileInfo& o) : filename(o.filename), lifetime(o.lifetime), data(o.data), size(o.size), refcount(o.refcount), prepared(false) { if(refcount!=NULL) ++(*refcount); }
00135     //! assignment operator, adds reference to the source's data (shallow copy)
00136     FileInfo& operator=(const FileInfo& o) { 
00137       release();
00138       filename=o.filename; lifetime=o.lifetime; data=o.data; size=o.size; refcount=o.refcount;
00139       if(refcount!=NULL)
00140         ++(*refcount); 
00141       return *this;
00142     }
00143     //! destructor
00144     virtual ~FileInfo() { release(); }
00145     
00146     virtual void prepare(); //!< make sure data is in physical memory for imminent usage
00147     virtual void done(); //!< we can let the data out of memory if needed
00148     virtual void release(); //!< if data is in an allocated region, free it
00149     
00150     const char* getData() const { return data; }
00151     size_t getSize() const { return size; }
00152     void setData(char* d, size_t s) { release(); data=d; size=s; refcount=new unsigned int; *refcount=1; }
00153     bool isPrepared() const { return prepared; }
00154     
00155     std::string filename; //!< the path to the file to load
00156     double lifetime; //!< duration for which this frame is "current", before next frame should be sent
00157   protected:
00158     char* data; //!< loaded/parsed contents of #filename, all ready to send, just need to copy into message
00159     size_t size; //!< size of buffer pointed to by #data (may be decompressed/processed, different than file size...)
00160     unsigned int* refcount; //!< maintain a reference count of the #data (just across FileInfo instances...)
00161     bool prepared; //!< true if prepare() has been called
00162   };
00163   
00164   //! calls prepare on @a fi, dumping diagnostic info if verbose is high enough
00165   virtual void preprepare(const FileSystemDataSource::files_t::iterator& fi);
00166   
00167   //! creates a new entry on #files, virtual to allow subclasses to use a FileInfo subclass with more meta data (e.g. see FileSystemImageSource::ImageInfo)
00168   virtual void enqueueFile(const std::string& name, double lifetime) { files.push_back(new FileInfo(name,lifetime)); } 
00169   
00170   files_t files; // collection of FileInfo entries
00171   files_t::iterator curfile; //!< an iterator referencing #files -- indicates next file to send
00172   double initialDelay; //!< milliseconds to wait before sending first frame
00173   double nextTime; //!< timestamp that #curfile should be sent
00174   bool indexed; //!< true if the file list was specified by an index file
00175   unsigned int freezeTime; //!< time at which doFreeze was called
00176   const plist::Primitive<double>* timeScale; //!< simulator's timeScale parameter, so we can register for updates when it changes
00177   LoggedDataDriver& parent; //!< device driver this is a member of
00178   double actualLoopTime; //!< time it would take to run through all of the loaded frames
00179   double naturalLoopTime; //!< time it would take to run through all of the frames as set immediately after load (i.e. no setLoopTime())
00180   Thread::Lock lock; //!< don't be in advance() while modifying file list
00181   bool registered; //!< synced to registerSource/deregisterSource so we don't start the thread if not actually in use
00182   
00183 private:
00184   FileSystemDataSource(const FileSystemDataSource&); //!< don't call
00185   FileSystemDataSource& operator=(const FileSystemDataSource&); //!< don't call
00186 };
00187 
00188 /*! @file
00189  * @brief 
00190  * @author Ethan Tira-Thompson (ejt) (Creator)
00191  */
00192 
00193 #endif

Tekkotsu Hardware Abstraction Layer 5.1CVS
Generated Mon May 9 05:01:38 2016 by Doxygen 1.6.3