home *** CD-ROM | disk | FTP | other *** search
/ ftp.hitl.washington.edu / ftp.hitl.washington.edu.tar / ftp.hitl.washington.edu / pub / people / peter / ER / ECG_driver.cxx < prev    next >
C/C++ Source or Header  |  1998-07-07  |  14KB  |  563 lines

  1. /*
  2.  ECG_driver.cc
  3. */
  4.  
  5. #include "ECG_driver.h"
  6.  
  7. #include <iostream.h>
  8. #include <vector.h>
  9. #include <map.h>
  10. #include <math.h>
  11.  
  12. #include "v3dSystem.h"
  13. #include "v3dUniverse.h"
  14.  
  15. //#define TIMESTAMP    // Time-stamp data changes.
  16.  
  17. #ifdef TIMESTAMP
  18. #include "timestamp.h"
  19. #endif
  20.  
  21. ///////////////////////////
  22. //    ECGDriver    //
  23. /////////////////////////
  24.  
  25. //const double ECGDriver::ms_Interval = 25.0;    // 25 ms per interval
  26. const double ECGDriver::ms_Interval = 40.0;    // 40 ms per interval
  27.  
  28. template<class T>
  29. vector<T> to_vec (int num_values, T *data_ary)
  30. {
  31.         vector<T> new_vec;
  32.         for (int i = 0; i < num_values; ++i)
  33.                 new_vec.push_back (data_ary[i]);
  34.         return new_vec;
  35. }
  36.  
  37. #include <stdio.h>
  38.  
  39. bool
  40. ECGDriver::read_data (char *filename)
  41. {
  42.     FILE *rhythm_fp = fopen(filename, "r");
  43.     if (rhythm_fp == NULL) {
  44.         cerr << "ECGDriver::read_data: Error opening file: " <<
  45.                         filename << endl;
  46.         return false;
  47.     }
  48.  
  49.     ECG_DATA_TYPE    alt;
  50.     int    p, qrs, t;
  51.  
  52.     vector<ECG_DATA_TYPE> alt_vec;
  53.         vector<char> p_vec, qrs_vec, t_vec;
  54.  
  55.     while (!feof(rhythm_fp)) {
  56.         fscanf (rhythm_fp, "%f %d %d %d", &alt, &p, &qrs, &t);
  57.         if (feof(rhythm_fp))
  58.             break;
  59.         alt_vec.push_back((ECG_DATA_TYPE)alt);
  60.         p_vec.push_back((char)p);
  61.         qrs_vec.push_back((char)qrs);
  62.         t_vec.push_back((char)t);
  63.     }
  64.  
  65.     test_values_.push_back(alt_vec);
  66.     P_values_.push_back(p_vec);
  67.     QRS_values_.push_back(qrs_vec);
  68.     T_values_.push_back(t_vec);
  69.  
  70.     fclose (rhythm_fp);
  71.  
  72.     return true;
  73. }
  74.  
  75. ECGDriver::ECGDriver() : v3dEventSender()
  76. {
  77.     read_data ("normal.data");
  78.     read_data ("VT.data");
  79.     read_data ("normal2.data");
  80.     read_data ("heart_block.data");
  81.     read_data ("PVC.data");
  82.     read_data ("flatline.data");
  83.  
  84.     data_list = 0;
  85.     P_list = 0;
  86.     QRS_list = 0;
  87.     T_list = 0;
  88.  
  89.     // Register the driver with the current universe.
  90.     // Later, the universe should be passed as a parameter.
  91.     v3dSystem::GetCurrentUniverse()->RegisterEventSender(this);
  92.  
  93.     // Register an event to tell receivers that new data has arrived.
  94.     RegisterEvent(new ECGDataUpdateEvent);
  95.  
  96.     // Register an event to tell receivers that the data stream has been
  97.     // switched.
  98.     data_switch_event_ = new ECGDataSwitchEvent;
  99.     data_switch_event_->SetActivityLevel(Inactive);
  100.         // The data switch event must be manually fired by the driver.
  101.     RegisterEvent(data_switch_event_);
  102.  
  103.     Unpause();
  104.     using_sequence_ = false;
  105.     using_fixed_range_ = false;
  106.  
  107.     switch_data (0);
  108. }
  109.  
  110. ECGDriver::ECGDriver(char *sequence_filename, ECG_DATA_TYPE min_val,
  111.     ECG_DATA_TYPE max_val) : v3dEventSender()
  112. {
  113.     // Open the file containing the sequence of ECG rhythms to play.
  114.     FILE *fp = fopen(sequence_filename, "r");
  115.     if (fp == NULL) {
  116.         cerr << "ECGDriver::ECGDriver: Error opening sequence file: " <<
  117.                         sequence_filename << endl;
  118.         return;
  119.     }
  120.  
  121.     // Read number of rhythms in this sequence.
  122.     int num_rhythms;
  123.     map <char, int, less<char> > code_map;
  124.     fscanf (fp, "%d", &num_rhythms);
  125. cerr << "Number of rhythms: " << num_rhythms << endl;
  126.  
  127.     for (int i = 0; i < num_rhythms; ++i) {
  128.         char rhythm_code[20], rhythm_filename[255];
  129.         fscanf (fp, "%s %s", &rhythm_code, &rhythm_filename);
  130.         if (feof (fp))
  131.             break;
  132. cerr << "Reading file " << rhythm_filename << ", code " << rhythm_code[0] << endl;
  133.         code_map[rhythm_code[0]] = i;
  134.         read_data (rhythm_filename);
  135.     }
  136.  
  137.     while (!feof(fp)) {
  138.         char rhythm_code[20];
  139.         int cycle_count;
  140.         fscanf (fp, "%s %d", &rhythm_code, &cycle_count);
  141.         if (feof(fp))
  142.             break;
  143. //cerr << "Rhythm code: " << rhythm_code[0] << " Count: " << cycle_count << endl;
  144.         RhythmSequenceNode sequence_node;
  145.         map <char, int, less<char> >::iterator finder
  146.             = code_map.find (rhythm_code[0]);
  147.         if (finder == code_map.end()) {
  148.             cerr << "ECGDriver: Error: code " << rhythm_code[0] <<
  149.                 " is undefined in file " << sequence_filename <<
  150.                 ".  Ignoring..." << endl;
  151.             continue;
  152.         }
  153.         
  154.         sequence_node.rhythm_no = (*finder).second;
  155.         sequence_node.cycle_count = cycle_count;
  156.         master_sequence_.push_back(sequence_node);
  157.     }
  158.  
  159.     fclose (fp);
  160.  
  161.     rhythm_sequence_ = master_sequence_;
  162.  
  163.     data_list = 0;
  164.     P_list = 0;
  165.     QRS_list = 0;
  166.     T_list = 0;
  167.  
  168.     // Register the driver with the current universe.
  169.     // Later, the universe should be passed as a parameter.
  170.     v3dSystem::GetCurrentUniverse()->RegisterEventSender(this);
  171.  
  172.     // Register an event to tell receivers that new data has arrived.
  173.     RegisterEvent(new ECGDataUpdateEvent);
  174.  
  175.     // Register an event to tell receivers that the data stream has been
  176.     // switched.
  177.     data_switch_event_ = new ECGDataSwitchEvent;
  178.     data_switch_event_->SetActivityLevel(Inactive);
  179.         // The data switch event must be manually fired by the driver.
  180.     RegisterEvent(data_switch_event_);
  181.  
  182.     // Register an event to tell receivers that the rhythm sequence has
  183.     // ended.
  184.     sequence_end_event_ = new ECGSequenceEndEvent;
  185.     sequence_end_event_->SetActivityLevel(Inactive);
  186.         // The sequence end event must be manually fired by the driver.
  187.     RegisterEvent(sequence_end_event_);
  188.  
  189.     using_sequence_ = true;
  190.     if (max_val == min_val)
  191.         using_fixed_range_ = false;
  192.     else {
  193.         data_range_.maximum_value = max_val;
  194.         data_range_.minimum_value = min_val;
  195.         using_fixed_range_ = true;
  196.     }
  197.  
  198.     switch_data (0);
  199.  
  200.     Unpause();
  201. }
  202.  
  203. ECGDriver::~ECGDriver()
  204. {
  205.     delete [] data_list;
  206.     delete [] P_list;
  207.     delete [] QRS_list;
  208.     delete [] T_list;
  209. }
  210.  
  211. void
  212. ECGDriver::TestEvents()
  213. {
  214.     // Update the ECG driver index.
  215.     if (!IsPaused()) {
  216.         if (using_sequence_)
  217.             update_current_sequence_index();
  218.         else
  219.             update_current_index();
  220.         v3dEventSender::TestEvents();
  221.  
  222.     } else {
  223.  
  224.         // Next, tell all event senders registered with this object to
  225.         // test their events.
  226.         EventSenderVector::iterator event_sender_iter
  227.             = event_senders_.begin();
  228.         for (; event_sender_iter != event_senders_.end();
  229.                 ++event_sender_iter)
  230.             (*event_sender_iter)->TestEvents ();
  231.     }
  232. }
  233.  
  234. // ECGDriver::Reset
  235. //    Reset the sequence data stream.
  236. void
  237. ECGDriver::Reset()
  238. {
  239.     rhythm_sequence_ = master_sequence_;
  240.     if (rhythm_sequence_.size())
  241.         using_sequence_ = true;
  242.     switch_data(0);
  243. }
  244.  
  245. ECG_DATA_RANGE
  246. ECGDriver::switch_data (int set_no)
  247. {
  248.     int    set_size, num_cycles;
  249.     if (rhythm_sequence_.size()) {
  250.         current_set_ = (*rhythm_sequence_.begin()).rhythm_no;
  251. cerr << "Next set in sequence: " << current_set_;
  252.         // Choose set 0 if the specified set is out of range.
  253.         if (current_set_ >= test_values_.size()) {
  254. cerr << " Set out of range!  Using set 0.";
  255.             current_set_ = 0;
  256.         }
  257.         set_size = test_values_[current_set_].size();
  258. cerr << " size: " << set_size;
  259.         num_cycles = (*rhythm_sequence_.begin()).cycle_count;
  260. cerr << " number of cycles: " << num_cycles;
  261.         rhythm_sequence_.pop_front();
  262. cerr << endl;
  263.     } else {
  264.         // A negative set number parameter increments the current set
  265.         // number.
  266.         if (set_no < 0) 
  267.             ++current_set_;
  268.         else
  269.             current_set_ = set_no;
  270.         // Choose set 0 if the specified set is out of range.
  271.         if (current_set_ >= test_values_.size())
  272.             current_set_ = 0;
  273.         set_size = test_values_[current_set_].size();
  274.         num_cycles = 100 / set_size + 1;
  275.     }
  276.  
  277. #ifdef TIMESTAMP
  278.     // For time-stamping purposes.
  279.     char tmp_buff[255];
  280.     sprintf (tmp_buff, "ECG data switch: rhythm %d", current_set_);
  281.     TrackedEvent *ECG_data_switch_event
  282.         = new TrackedEvent(TrackedEvent::SystemEvent, 10 + current_set_, tmp_buff, false);
  283.  
  284.     TimestampedEvent::AddEvent(ECG_data_switch_event);
  285. #endif    // TIMESTAMP
  286.  
  287.     int    p_set_size = P_values_[current_set_].size();
  288.     max_index_ = set_size * num_cycles;
  289. cerr << "Set size: " << set_size << " Number of cycles: " << num_cycles <<
  290.     " Max index: " << max_index_ << endl;
  291.  
  292.     // Allocate a new array to hold the data values, and copy them from
  293.     // the vector of values.
  294.     delete [] data_list;
  295.     delete [] P_list;
  296.     delete [] QRS_list;
  297.     delete [] T_list;
  298.  
  299.     data_list = new ECG_DATA_TYPE [max_index_];
  300.     P_list = new char [max_index_];
  301.     QRS_list = new char [max_index_];
  302.     T_list = new char [max_index_];
  303.  
  304.     for (int i = 0; i < max_index_; ++i) {
  305.         data_list[i] = test_values_[current_set_][i % set_size];
  306.         P_list[i] = P_values_[current_set_][i % p_set_size];
  307.         QRS_list[i] = QRS_values_[current_set_][i % set_size];
  308.         T_list[i] = T_values_[current_set_][i % p_set_size];
  309.     }
  310.  
  311.     // Set the index to the start of the data.
  312.     reset_current_index();
  313.  
  314.     // Get the ranges of the data.
  315.     if (!using_fixed_range_) {
  316.  
  317.     data_range_.maximum_value = data_list[0];
  318.     data_range_.minimum_value = data_list[0];
  319.     for (int i = 1; i < set_size; ++i) {
  320.         if (data_list[i] > data_range_.maximum_value)
  321.             data_range_.maximum_value = data_list[i];
  322.         if (data_list[i] < data_range_.minimum_value)
  323.             data_range_.minimum_value = data_list[i];
  324.     }
  325.     if (fabs(data_range_.maximum_value) > fabs(data_range_.minimum_value))
  326.         data_range_.minimum_value = - fabs(data_range_.maximum_value);
  327.     else
  328.         data_range_.maximum_value = fabs(data_range_.minimum_value);
  329.  
  330.     }    // Not using fixed range end.
  331.  
  332.     // Tell all interested clients that the data stream has been switched.
  333.     data_switch_event_->InvokeHandlers(0);
  334.  
  335.     return data_range_;
  336. }
  337.  
  338. void
  339. ECGDriver::ECG_update_callback(const v3dEventMessage *message)
  340. {
  341.     ((ECGDriver *)message->GetEventReceiver())->update_current_index();
  342. }
  343.  
  344. // usec_diff
  345. //    Calculate the difference in microseconds between the two times
  346. //    passed in.
  347. inline float
  348. usec_diff (const timeval& current_time, const timeval& past_time)
  349. {
  350.     return (current_time.tv_sec - past_time.tv_sec) * 1000000 +
  351.         current_time.tv_usec - past_time.tv_usec;
  352. }
  353.  
  354. // ECGDriver::update_current_index
  355. //    Changes the current index to the ECG data depending on how much
  356. //    time has elapsed since the last update.
  357. //    Each value in the array represents a piece of ECG data read at
  358. //    40ms intervals.
  359. int
  360. ECGDriver::update_current_index ()
  361. {
  362.     timeval current_time;
  363.  
  364. //cerr << "clock / sec: " << CLOCKS_PER_SEC;
  365.     gettimeofday (¤t_time);
  366. //cerr << " elapsed clock: " << current_time.tv_usec - last_time_.tv_usec;
  367. //cerr << " elapsed int: " << ((current_time.tv_sec - last_time_.tv_sec) *
  368. //        1000000 + current_time.tv_usec - last_time_.tv_usec)
  369. //         / (1000 * ms_Interval);
  370. //cerr << endl;
  371.  
  372. //    true_index_ += ((current_time.tv_sec - last_time_.tv_sec) * 1000000 +
  373. //        current_time.tv_usec - last_time_.tv_usec) /
  374. //        (1000 * ms_Interval);
  375.     true_index_ += usec_diff (current_time, last_time_) /
  376.         (1000 * ms_Interval);
  377.     while (true_index_ >= max_index_)
  378.         true_index_ -= max_index_;
  379.     current_index_ = (int) ffloor (true_index_);
  380.     last_time_ = current_time;
  381.  
  382. //cerr << " true index: " << true_index_;
  383. //cerr << " current index: " << current_index_ << endl;
  384.     return current_index_;
  385. }
  386.  
  387. int
  388. ECGDriver::reset_current_index ()
  389. {
  390. //    last_time_ = clock();
  391.     gettimeofday(&last_time_);
  392.     true_index_ = 0;
  393.     return current_index_ = 0;
  394. }
  395.  
  396. void
  397. ECGDriver::ECG_sequence_update_callback(const v3dEventMessage *message)
  398. {
  399.     ((ECGDriver *)message->GetEventReceiver())->update_current_sequence_index();
  400. }
  401.  
  402.  
  403. // ECGDriver::update_current_sequence_index
  404. //    Changes the current index to the ECG data depending on how much
  405. //    time has elapsed since the last update.
  406. //    Each value in the array represents a piece of ECG data read at
  407. //    40ms intervals.
  408. int
  409. ECGDriver::update_current_sequence_index ()
  410. {
  411. #ifdef TIMESTAMP
  412.     static TrackedEvent sequence_end_event(TrackedEvent::SystemEvent, 99,
  413.         "Rhythm sequence finished");
  414. #endif    // TIMESTAMP
  415.  
  416.     timeval current_time;
  417.  
  418.     gettimeofday (¤t_time);
  419.  
  420.     true_index_ += usec_diff (current_time, last_time_) /
  421.         (1000 * ms_Interval);
  422.  
  423.     if (true_index_ >= max_index_) {
  424.         while (true_index_ >= max_index_)
  425.             true_index_ -= max_index_;
  426.         current_index_ = (int) ffloor (true_index_);
  427.         // Switch the data if there is more data in the sequence.
  428.         if (rhythm_sequence_.size()) {
  429. cerr << "Switching to new sequence." << endl;
  430.             switch_data();
  431.         } else {
  432. cerr << "Sequence completed." << endl;
  433. #ifdef TIMESTAMP
  434.             TimestampedEvent::AddEvent(&sequence_end_event);
  435. #endif    // TIMESTAMP
  436.             // Tell all interested clients that the rhythm sequence
  437.             // has finished.
  438. /*
  439.             using_sequence_ = false;
  440.             Pause();
  441.             sequence_end_event_->InvokeHandlers(0);
  442. */
  443.             Reset();
  444.         }
  445.     } else
  446.         current_index_ = (int) ffloor (true_index_);
  447.     last_time_ = current_time;
  448.  
  449. //cerr << " true index: " << true_index_;
  450. //cerr << " current index: " << current_index_ << endl;
  451.     return current_index_;
  452. }
  453.  
  454.  
  455. /////////////////////////////////////////////////////////////////////////////
  456. // Events
  457.  
  458. ECGDataUpdateEvent::ECGDataUpdateEvent() : v3dEvent(ECG_DATA_UPDATE)
  459. {
  460. }
  461.  
  462. void ECGDataUpdateEvent::Test()
  463. {
  464.     InvokeHandlers(0);
  465. }
  466.  
  467. ECGDataSwitchEvent::ECGDataSwitchEvent() : v3dEvent(ECG_DATA_SWITCH)
  468. {
  469. }
  470.  
  471. void ECGDataSwitchEvent::Test()
  472. {
  473.     // The data switch event never fires by itself -- it must always be
  474.     // fired from within the ECG driver.
  475.     return;
  476. }
  477.  
  478. ECGSequenceEndEvent::ECGSequenceEndEvent() : v3dEvent(ECG_SEQUENCE_END)
  479. {
  480. }
  481.  
  482. void ECGSequenceEndEvent::Test()
  483. {
  484.     // The sequence end event never fires by itself -- it must always be
  485.     // fired from within the ECG driver.
  486.     return;
  487. }
  488.  
  489.  
  490.  
  491. ////////////////////////////////////////////////////////////////////////////
  492.  
  493. ECG_DATA_TYPE
  494. ECGDriver::GetMaximumValue () const
  495. {
  496.     return data_range_.maximum_value;
  497. }
  498.  
  499. ECG_DATA_TYPE
  500. ECGDriver::GetMinimumValue () const
  501. {
  502.     return data_range_.minimum_value;
  503. }
  504.  
  505. ECG_DATA_RANGE
  506. ECGDriver::GetDataRange () const
  507. {
  508.     return data_range_;
  509. }
  510.  
  511. ECG_DATA_TYPE
  512. ECGDriver::GetData (int index) const
  513. {
  514.     return data_list[index];
  515. }
  516.  
  517. int
  518. ECGDriver::GetCurrentDataIndex () const
  519. {
  520.     return current_index_;
  521. }
  522.  
  523. int
  524. ECGDriver::GetNextDataIndex (int last_index) const
  525. {
  526.     return (++last_index >= max_index_) ? 0 : last_index;
  527. }
  528.  
  529. int
  530. ECGDriver::GetPreviousDataIndex (int last_index) const
  531. {
  532.     return (--last_index < 0) ? max_index_ - 1 : last_index;
  533. }
  534.  
  535. void
  536. ECGDriver::Pause()
  537. {
  538.         paused_ = true;
  539. }
  540.  
  541. void
  542. ECGDriver::Unpause()
  543. {
  544.         paused_ = false;
  545. }
  546.  
  547. bool
  548. ECGDriver::IsPaused() const
  549. {
  550.     return paused_;
  551. }
  552.  
  553. void
  554. ECGDriver::TogglePause()
  555. {
  556.     if (paused_)
  557.         Unpause();
  558.     else
  559.         Pause();
  560. }
  561.  
  562.  
  563.