Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Examples  

gadget::InputLogger Class Reference

Input data logger. More...

#include <InputLogger.h>

Collaboration diagram for gadget::InputLogger:

Collaboration graph
[legend]
List of all members.

Public Types

enum  State { Inactive, Recording, Playing, Paused }
 List of states that the Logger can be in. More...


Public Methods

 InputLogger ()
virtual ~InputLogger ()
 Destructor. More...

virtual bool config (jccl::ConfigElementPtr element)
 Configure the logger. More...

void process ()
 Do input logging processing. More...

Recording interface
void startRecording ()
void stopRecording ()
void stampRecord ()
 Collect a stamp in the recording. More...

Playback interface
void load (std::string logFilename)
 Load a log file. More...

void play ()
 Play the currently active log. More...

void stop ()
 Stop playing a log. More...

void pause ()
 Pause log playback. More...

std::string getStamp ()
 Get the stamp for the most recent sample. More...

Query methods
bool getState ()

Protected Methods

void compressSamples ()
 Eliminates duplicates in the current sampled data It ignores the timestamp attribute. More...

Internal helpers
void addRecordingSample ()
 Add a recording sample to the current dom tree. More...

void playNextSample ()
void limitFramerate ()
 Limit the framerate to the speed configured. More...


Detailed Description

Input data logger.

Definition at line 54 of file InputLogger.h.


Member Enumeration Documentation

enum gadget::InputLogger::State
 

List of states that the Logger can be in.

Enumeration values:
Inactive  The Logger is Inactive to be told what to do.

ie. doing nothing

Recording  The Logger is current recording.
Playing  The Logger is currently playing.
Paused  The Logger is currently paused.

Definition at line 138 of file InputLogger.h.

00139    {
00140       Inactive,   
00141       Recording,  
00142       Playing,    
00143       Paused      
00144    };


Constructor & Destructor Documentation

gadget::InputLogger::InputLogger   [inline]
 

Definition at line 57 of file InputLogger.h.

00058       : mCurState(Inactive), mSleepFramesLeft(0), mLimitFrameRate(false)
00059    {;}

virtual gadget::InputLogger::~InputLogger   [inline, virtual]
 

Destructor.

Definition at line 62 of file InputLogger.h.

00063    {;}


Member Function Documentation

bool gadget::InputLogger::config jccl::ConfigElementPtr    element [virtual]
 

Configure the logger.

Definition at line 88 of file InputLogger.cpp.

References gadgetDBG_INPUT_MGR, and gadget::BaseDeviceInterface::init.

00089 {
00090    std::string start_name = element->getProperty<std::string>("start_digital");
00091    std::string stamp_name = element->getProperty<std::string>("stamp_digital");
00092 
00093    mStartStopButton.init(start_name);
00094    mStampButton.init(stamp_name);
00095 
00096    int max_frame_rate = element->getProperty<int>("max_framerate");
00097    mCompressFactor = element->getProperty<unsigned>("compress_factor");
00098 
00099    // Get ignore attribs and elems for compressing
00100    unsigned num_ignore_elems, num_ignore_attribs;
00101    num_ignore_elems = element->getNum("ignore_elems");
00102    num_ignore_attribs = element->getNum("ignore_attribs");
00103 
00104    for(unsigned i=0;i<num_ignore_elems;i++)
00105    { mIgnoreElems.push_back(element->getProperty<std::string>("ignore_elems",i)); }
00106 
00107    for(unsigned i=0;i<num_ignore_attribs;i++)
00108    { mIgnoreAttribs.push_back(element->getProperty<std::string>("ignore_attribs",i)); }
00109 
00110    if(max_frame_rate > 0)   // If we are supposed to limit frame rate
00111    {
00112       mLimitFrameRate = true;
00113 
00114       mPrevFrameTimestamp.setNow();             // Initialize value
00115       mMinFrameTime.set( (1000/max_frame_rate), vpr::Interval::Msec);
00116    }
00117 
00118    vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL) << "\n--- LOGGER: Configured ---\n" << vprDEBUG_FLUSH;
00119    vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL) << "StartStop: " << start_name << std::endl
00120                                                      << "Stamp: " << stamp_name << std::endl
00121                                                      << "Max framerate: " << max_frame_rate << std::endl
00122                                                      << "Min frametime: " << mMinFrameTime.msec() << "ms" << std::endl << vprDEBUG_FLUSH;
00123 
00124    return true;
00125 }

void gadget::InputLogger::process  
 

Do input logging processing.

This method is called by the input manager each update frame to allow the logger to do any processing that it needs to complete.

Definition at line 142 of file InputLogger.cpp.

References addRecordingSample, limitFramerate, Playing, playNextSample, Recording, stampRecord, startRecording, and stopRecording.

00143 {
00144    // Get state of control keys
00145    // Note, because of how this is called this sees the state one frame late
00146    // ie. If toggle on is true here it is NOT true in the data being saved
00147    const bool start_stop_triggered(mStartStopButton->getData() == Digital::TOGGLE_ON);
00148    const bool stamp_triggered(mStampButton->getData() == Digital::TOGGLE_ON);
00149 
00150    if(0 == mSleepFramesLeft)
00151    {
00152       // Check for control keys
00153       if(Playing != mCurState)
00154       {
00155          if(start_stop_triggered)
00156          {
00157             if(Recording == mCurState)
00158             {  stopRecording(); }
00159             else
00160             {  startRecording(); }
00161          }
00162          else if(stamp_triggered && (Recording == mCurState))
00163          {  stampRecord(); }
00164       }
00165 
00166       if(Recording == mCurState)
00167       {
00168          addRecordingSample();
00169 
00170          if(mLimitFrameRate)
00171          {  limitFramerate(); }
00172       }
00173       else if(Playing == mCurState)
00174       {
00175          playNextSample();
00176       }
00177    }
00178    else
00179    {
00180       vprDEBUG(vprDBG_ALL, vprDBG_CONFIG_LVL) << "InputLogger: Sleeping: " << mSleepFramesLeft << std::endl << vprDEBUG_FLUSH;
00181       mSleepFramesLeft--;
00182    }
00183 }

void gadget::InputLogger::startRecording  
 

Definition at line 191 of file InputLogger.cpp.

References gadgetDBG_INPUT_MGR, and Recording.

Referenced by process.

00192 {
00193    vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL) << "\n--- LOGGER: startRecording ---\n" << vprDEBUG_FLUSH;
00194 
00195    // -- Get recording filename
00196    std::cout << "/n/n------- LOGGER ------\nEnter log filename:" << std::flush;
00197    std::string file_name;
00198    //std::string file_name("test_logging.xml");
00199    std::cin >> file_name;
00200    std::cout << "\nUsing file: " << file_name << std::endl;
00201 
00202    mRecordingFilename = file_name;
00203 
00204    // -- Init recording
00205    cppdom::ContextPtr ctx( new cppdom::Context );
00206    mRootNode = cppdom::NodePtr(new cppdom::Node("gadget_logger", ctx ));
00207 
00208    mCurState = Recording;
00209 }

void gadget::InputLogger::stopRecording  
 

Definition at line 211 of file InputLogger.cpp.

References compressSamples, gadgetDBG_INPUT_MGR, and Inactive.

Referenced by process.

00212 {
00213    vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL) << "\n--- LOGGER: stopRecording ---\n" << vprDEBUG_FLUSH;
00214    vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL) << "Done recording\n"
00215                                     << "Saving data to: " << mRecordingFilename << std::endl << vprDEBUG_FLUSH;
00216 
00217    // Compress the data before saving
00218    std::cout << "Before compressing: size:" << mRootNode->getChildren().size() << std::endl;
00219    compressSamples();
00220    std::cout << "After compressing: size:" << mRootNode->getChildren().size() << std::endl;
00221 
00222    std::ofstream out_file;
00223    out_file.exceptions(std::ofstream::badbit | std::ofstream::failbit);
00224    try
00225    {
00226       out_file.open(mRecordingFilename.c_str());
00227       mRootNode->save(out_file);
00228       out_file.flush();
00229       out_file.close();
00230    }
00231 #if defined(__GNUC__) && __GNUC__ == 2 && __GNUC_MINOR__ == 96
00232    catch(...)
00233    {
00234       std::cerr << "Unknown error saving file." << std::endl;
00235       if(out_file.is_open())
00236       {  out_file.close(); }
00237    }
00238 #else
00239    catch(std::ofstream::failure& se)
00240    {
00241       std::cerr << "IOS failure saving file: desc:" << se.what() << std::endl;
00242       if(out_file.is_open())
00243       {  out_file.close(); }
00244    }
00245    catch(...)
00246    {
00247       std::cerr << "Unknown error saving file." << std::endl;
00248    }
00249 #endif
00250 
00251    mCurState = Inactive;
00252    mSleepFramesLeft = 10;     // Wait 10 frames until we start processing anything again
00253 }

void gadget::InputLogger::stampRecord  
 

Collect a stamp in the recording.

Definition at line 255 of file InputLogger.cpp.

References Recording.

Referenced by process.

00256 {
00257    vprASSERT(Recording == mCurState && "Tried to stamp input while not recording");
00258 
00259    // -- Get recording filename
00260    char tag_name[1024];
00261    std::cout << "/n/n------- LOGGER ------\nEnter stamp id:" << std::flush;
00262    std::string stamp_id;
00263    //std::cin >> stamp_id;
00264    scanf("%s", tag_name);
00265    stamp_id = std::string(tag_name);
00266    std::cout << "\nStamping with: " << stamp_id << std::endl;
00267 
00268    cppdom::NodePtr stamp_node(new cppdom::Node("stamp", mRootNode->getContext()));
00269    stamp_node->setAttribute("id", stamp_id);
00270 
00271    mRootNode->addChild(stamp_node);
00272 }

void gadget::InputLogger::load std::string    logFilename
 

Load a log file.

Parameters:
logFilename  - The name of the log file to load

Definition at line 277 of file InputLogger.cpp.

References Inactive.

00278 {
00279    vprASSERT(Inactive == mCurState && "Tried to load a file while logger is active");
00280 
00281    std::cout << "InputLogger: Loading file: " << logFilename << std::endl;
00282 
00283    // Create new root to read into
00284    cppdom::ContextPtr ctx( new cppdom::Context );
00285    mRootNode = cppdom::NodePtr(new cppdom::Node("not_set", ctx ));
00286 
00287    std::ifstream in_file;
00288    in_file.exceptions(std::ifstream::badbit | std::ifstream::failbit);
00289    try
00290    {
00291       in_file.open(logFilename.c_str(), std::ios::in);
00292       mRootNode->load(in_file, ctx);
00293       in_file.close();
00294    }
00295 #if defined(__GNUC__) && __GNUC__ == 2 && __GNUC_MINOR__ == 96
00296    catch(...)
00297    {
00298       std::cerr << "Unknown error loading file." << std::endl;
00299       if(in_file.is_open())
00300       {  in_file.close(); }
00301    }
00302 #else
00303    catch(std::ifstream::failure& se)
00304    {
00305       std::cerr << "IOS failure saving file: desc:" << se.what() << std::endl;
00306       if(in_file.is_open())
00307       {  in_file.close(); }
00308    }
00309    catch(...)
00310    {
00311       std::cerr << "Unknown error loading file." << std::endl;
00312    }
00313 #endif
00314 
00315    vprDEBUG(vprDBG_ALL, vprDBG_STATE_LVL) << "InputLogger: Loaded file: num_samples:" << mRootNode->getChildren().size() << std::endl << vprDEBUG_FLUSH;
00316 }

void gadget::InputLogger::play  
 

Play the currently active log.

Definition at line 325 of file InputLogger.cpp.

References Inactive, and Playing.

00326 {
00327    vprASSERT(mCurState == Inactive);
00328 
00329    if(mRootNode.get() == NULL)
00330    {
00331       vprDEBUG(vprDBG_ALL, vprDBG_WARNING_LVL) << "Logger::play: Null root node, so can't play.\n" << vprDEBUG_FLUSH;
00332       return;
00333    }
00334 
00335    mNextSample_i = mRootNode->getChildren().begin();
00336    mEndSample_i = mRootNode->getChildren().end();
00337    mActiveStamp.clear();
00338 
00339    if(mNextSample_i == mEndSample_i)
00340    {
00341       vprDEBUG(vprDBG_ALL, vprDBG_WARNING_LVL) << "Logger::play: Zero children, so can't play.\n" << vprDEBUG_FLUSH;
00342       return;
00343    }
00344 
00345    mCurState = Playing;
00346 }

void gadget::InputLogger::stop  
 

Stop playing a log.

Definition at line 349 of file InputLogger.cpp.

00350 {;
00351 }

void gadget::InputLogger::pause  
 

Pause log playback.

Definition at line 354 of file InputLogger.cpp.

00355 {;
00356 }

std::string gadget::InputLogger::getStamp  
 

Get the stamp for the most recent sample.

Returns:
Returns empty string if no active stamp.

Definition at line 361 of file InputLogger.cpp.

00362 {
00363    return mActiveStamp;
00364 }

bool gadget::InputLogger::getState   [inline]
 

Definition at line 112 of file InputLogger.h.

00113    {  return mCurState; }

void gadget::InputLogger::addRecordingSample   [protected]
 

Add a recording sample to the current dom tree.

  • Create the sample node
  • For each device in input manager
    • Create device node for the device (named after device)
    • Serialize device into a node
    • Add serialized dev node as child of dev node
    • Add dev node as child of sample node
  • Add sample node as child of root node

Definition at line 377 of file InputLogger.cpp.

References gadgetDBG_INPUT_MGR, gadget::Input::getInstanceName, and gadget::Input::writeObject.

Referenced by process.

00378 {
00379    vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL) << "LOGGER: adding sample.\n" << vprDEBUG_FLUSH;
00380 
00381    try
00382    {
00383       gadget::InputManager* input_mgr = gadget::InputManager::instance();
00384 
00385       cppdom::NodePtr sample_node(new cppdom::Node("sample", mRootNode->getContext()));
00386 
00387       // For each device
00388       for(InputManager::tDevTableType::iterator dev_i=input_mgr->mDevTable.begin();
00389           dev_i != input_mgr->mDevTable.end(); ++dev_i)
00390       {
00391          gadget::Input* cur_dev = (*dev_i).second;
00392          std::string dev_name = cur_dev->getInstanceName();
00393 
00394          cppdom::NodePtr dev_node(new cppdom::Node("device", mRootNode->getContext()));
00395          dev_node->setAttribute("dev_name", dev_name);
00396 
00397          vpr::XMLObjectWriter xml_writer;       // Create writer for the device
00398          cur_dev->writeObject(&xml_writer);
00399          cppdom::NodePtr serialized_dev_node = xml_writer.getRootNode();
00400          vprASSERT(serialized_dev_node.get() != NULL);
00401 
00402          dev_node->addChild(serialized_dev_node);  // Add the child node
00403          sample_node->addChild(dev_node);          // Add dev node to the sample
00404       }
00405 
00406       mRootNode->addChild(sample_node);
00407    }
00408    catch (cppdom::Error& ce)
00409    {
00410       std::cerr << "Cppdom Error [InputLogger::addRecordingSample]: " << ce.getString() << std::endl;
00411       std::cerr << "Info: " << ce.getInfo() << std::endl;
00412       vprASSERT(false);
00413    }
00414 }

void gadget::InputLogger::playNextSample   [protected]
 

Definition at line 429 of file InputLogger.cpp.

References gadgetDBG_INPUT_MGR, Inactive, and gadget::Input::readObject.

Referenced by process.

00430 {
00431    vprDEBUG_OutputGuard(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL, "InputLogger::playNextSample\n", "done playing sample\n");
00432 
00433    vprASSERT(mNextSample_i != mEndSample_i && "Overran the logger sample list");
00434    gadget::InputManager* input_mgr = gadget::InputManager::instance();
00435 
00436    cppdom::NodePtr next_node = (*mNextSample_i);
00437    vprASSERT(next_node->getName() == std::string("sample") && "Didn't get element of name sample");
00438 
00439    // For each device element
00440    cppdom::NodeList dev_nodes = next_node->getChildren();
00441    for(cppdom::NodeListIterator cur_dev_node=dev_nodes.begin(); cur_dev_node != dev_nodes.end(); ++cur_dev_node)
00442    {
00443       vprASSERT((*cur_dev_node)->getName() == std::string("device"));
00444       std::string dev_name = (*cur_dev_node)->getAttribute("dev_name").getValue<std::string>();
00445       cppdom::NodePtr serial_dev_node = *((*cur_dev_node)->getChildren().begin());
00446       vprASSERT(serial_dev_node.get() != NULL && "Got null serialized device node");
00447 
00448       gadget::Input* dev_ptr = input_mgr->getDevice(dev_name);
00449       if(NULL != dev_ptr)
00450       {
00451          vprDEBUG_OutputGuard(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL,
00452                               std::string("Reading device: ") + dev_name + std::string("\n"), "done reading");
00453 
00454          vpr::XMLObjectReader xml_reader(serial_dev_node);     // Create XML reader
00455          xml_reader.setAttrib("rim.timestamp.delta", 0);       // Hack for now to work around RIM
00456          dev_ptr->readObject(&xml_reader);                     // Deserialize the device
00457       }
00458       else
00459       {
00460          vprDEBUG(gadgetDBG_INPUT_MGR,vprDBG_WARNING_LVL) << "Skipping device: [" << dev_name
00461                                          << "]  Could not find it.\n" << vprDEBUG_FLUSH;
00462       }
00463    }
00464 
00465    // Increment next sample
00466    mNextSample_i++;
00467    mActiveStamp.clear();      // Clear the stamp for now
00468 
00469    if(mNextSample_i != mEndSample_i)
00470    {
00471       if( (*mNextSample_i)->getName() == std::string("stamp"))
00472       {
00473          mActiveStamp = (*mNextSample_i)->getAttribute("id").getValue<std::string>();
00474          mNextSample_i++;
00475          vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL) << "Logger: Got stamp: [" << mActiveStamp << "]\n" << vprDEBUG_FLUSH;
00476       }
00477    }
00478 
00479    if(mNextSample_i == mEndSample_i)   // If done playing
00480    {
00481       mCurState = Inactive;
00482       mSleepFramesLeft = 10;     // Wait 10 frames until we start processing anything again
00483       vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL) << "Logger: Done playing.\n" << vprDEBUG_FLUSH;
00484    }
00485 
00486 }

void gadget::InputLogger::limitFramerate   [protected]
 

Limit the framerate to the speed configured.

Precondition:
mLimitFrameRate == true
Postcondition:
Method will sleep until enough time passed to slow to configured framerate

Definition at line 488 of file InputLogger.cpp.

Referenced by process.

00489 {
00490    vprASSERT(mLimitFrameRate);
00491 
00492    vpr::Interval cur_frame_time = vpr::Interval::now() - mPrevFrameTimestamp;
00493    if(cur_frame_time < mMinFrameTime)
00494    {
00495       vpr::Interval sleep_time = (mMinFrameTime - cur_frame_time);
00496       std::cout << "Sleeping: " << sleep_time.msec() << "ms\n";
00497       vprASSERT(sleep_time.msec() > 0);
00498       vpr::System::msleep(sleep_time.msec());                     // Sleep
00499    }
00500 
00501    mPrevFrameTimestamp.setNow();
00502 }

void gadget::InputLogger::compressSamples   [protected]
 

Eliminates duplicates in the current sampled data It ignores the timestamp attribute.

Definition at line 504 of file InputLogger.cpp.

Referenced by stopRecording.

00505 {
00506    // Get the current children to compress
00507    cppdom::NodeList& nodes(mRootNode->getChildren());
00508    unsigned total_nodes_start = nodes.size();
00509 
00510    // Create a nice little progress bar for the compression
00511    boost::progress_display compress_progress(nodes.size());
00512 
00513    cppdom::NodeList::iterator cur_node = nodes.begin();
00514    if(nodes.end() == cur_node)
00515       return;
00516 
00517    cur_node++;       // Can't remove first node
00518    //unsigned node_index(0);
00519 
00520    // Compress the data
00521    // - While nodes left
00522    //   - If node is duplicate of one before it
00523    //     - Erase the node and goto next
00524    while(cur_node != nodes.end())
00525    {
00526       cppdom::NodeList::iterator dup_node = (cur_node-1);      // Initialize dup node to check
00527 
00528       /*
00529       std::cout << "-----------------------------------------------------------------------\n"
00530                 << "-----------------------------------------------------------------------\n"
00531                 << "Comparing nodes: index: " << node_index++ << std::endl;
00532       std::cout << "------ curnode:\n";
00533       (*cur_node)->save(std::cout, 1);
00534       std::cout << "------ dupnode:\n";
00535       (*dup_node)->save(std::cout, 1);
00536       std::cout << "------ Start comparison ----\n";
00537       */
00538 
00539       if((*cur_node)->isEqual( *dup_node, mIgnoreAttribs, mIgnoreElems))
00540       {
00541          cur_node = nodes.erase(cur_node);         // Remove the node and get next one
00542       }
00543       else
00544       {
00545          cur_node++;                               // Go to the next
00546       }
00547 
00548       compress_progress += 1;       // Progress a little bit
00549    }
00550 
00551    // --- Print results --- //
00552    std::cout << std::endl
00553              << "Compression: initial/compressed:" << total_nodes_start << "/" << nodes.size() << std::endl
00554              << "      ratio: " << float(nodes.size())/float(total_nodes_start) << std::endl;
00555 }


The documentation for this class was generated from the following files:
Generated on Sun May 2 14:26:53 2004 for Gadgeteer by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002