battery_monitor_treeview.cpp

00001
00002 /***************************************************************************
00003  *  battery_monitor_treeview.cpp - TreeView class for displaying the battery
00004  *                                 status of the robots
00005  *
00006  *  Created: Mon Apr 06 16:08:50 2009
00007  *  Copyright  2009  Daniel Beck
00008  *
00009  ****************************************************************************/
00010
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL file in the doc directory.
00022  */
00023
00024 #include "battery_monitor_treeview.h"
00025
00026 #include <blackboard/remote.h>
00027 #include <gui_utils/interface_dispatcher.h>
00028 #include <gui_utils/utils.h>
00029 #include <interfaces/BatteryInterface.h>
00030
00031 #include <cstring>
00032
00033 using namespace std;
00034 using namespace fawkes;
00035 
00036 /** @class BatteryMonitorTreeView tools/battery_monitor/battery_monitor_treeview.h
00037  * A treeview that retrieves battery data from the robots over remote
00038  * blackboard connections and displays those.
00039  * @author Daniel Beck
00040  */
00041 
00042 /** @class BatteryMonitorTreeView::BatteryRecord tools/battery_monitor/battery_monitor_treeview.h
00043  * Column record class for the battery monitor treeview.
00044  * @author Daniel Beck
00045  */
00046 
00047 /** @var BatteryMonitorTreeView::m_battery_record
00048  * Column record object to acces the columns of the storage object.
00049  */
00050 
00051 /** @var BatteryMonitorTreeView::m_battery_list
00052  * Storage object.
00053  */
00054 
00055 /** @var BatteryMonitorTreeView::m_remote_bbs
00056  * Map with remote blackboards: hostname -> remote blackboard.
00057  */
00058 
00059 /** @var BatteryMonitorTreeView::m_battery_interfaces
00060  * Map containing the battery interfaces: hostname -> battery interface
00061  */
00062 
00063 /** @var BatteryMonitorTreeView::m_interface_dispatcher
00064  * Interface dispatcher for the battery interfaces.
00065  */
00066 
00067 /** Constructor.
00068  * @param cobject base object type
00069  * @param ref_xml Glade XML object
00070  */
00071 BatteryMonitorTreeView::BatteryMonitorTreeView( BaseObjectType* cobject,
00072                                                 const Glib::RefPtr< Gnome::Glade::Xml >& ref_xml )
00073   : Gtk::TreeView( cobject )
00074 {
00075   m_battery_list = Gtk::ListStore::create( m_battery_record );
00076   set_model( m_battery_list );
00077
00078   append_column( "Host", m_battery_record.short_name );
00079   append_column_numeric( "Abs. SOC [%]", m_battery_record.absolute_soc, "%.1f" );
00080   append_column_numeric( "Rel. SOC [%]", m_battery_record.relative_soc, "%.1f" );
00081   append_column_numeric( "Voltage [V]", m_battery_record.voltage, "%.3f" );
00082   append_column_numeric( "Current [A]", m_battery_record.current, "%.3f" );
00083
00084   m_dlg_warning = dynamic_cast< Gtk::MessageDialog* >( get_widget( ref_xml, "dlgWarning" ) );
00085   m_dlg_warning->hide();
00086
00087   m_trigger_update.connect( sigc::mem_fun( *this, &BatteryMonitorTreeView::update ) );
00088
00089   m_relative_soc_threshold = 20.0;
00090 }
00091 
00092 /** Destructor. */
00093 BatteryMonitorTreeView::~BatteryMonitorTreeView()
00094 {
00095   for ( std::map< string, BatteryInterface* >::iterator biit = m_battery_interfaces.begin();
00096         biit != m_battery_interfaces.end();
00097         ++biit )
00098   {
00099     std::map< string, BlackBoard* >::iterator rbit;
00100     rbit = m_remote_bbs.find( biit->first );
00101
00102     std::map< string, InterfaceDispatcher* >::iterator idit;
00103     idit = m_interface_dispatcher.find( biit->first );
00104
00105     if ( rbit != m_remote_bbs.end() )
00106     {
00107       rbit->second->unregister_listener( idit->second );
00108       rbit->second->close( biit->second );
00109       delete rbit->second;
00110     }
00111   }
00112
00113   // delete interface dispatcher
00114   for ( std::map< string, InterfaceDispatcher* >::iterator i = m_interface_dispatcher.begin();
00115         i != m_interface_dispatcher.end();
00116         ++i )
00117   {
00118     delete i->second;
00119   }
00120
00121   // delete remote blackboards
00122   for ( std::map< string, BlackBoard* >::iterator i = m_remote_bbs.begin();
00123         i != m_remote_bbs.end();
00124         ++i )
00125   {
00126     delete i->second;
00127   }
00128
00129   delete m_dlg_warning;
00130 }
00131 
00132 /** Add given host.
00133  * @param h the host's hostname
00134  */
00135 void
00136 BatteryMonitorTreeView::add_host( const char* h )
00137 {
00138   string host(h);
00139
00140   BlackBoard* rbb;
00141   std::map< string, BlackBoard* >::iterator i = m_remote_bbs.find( host );
00142
00143   if ( i == m_remote_bbs.end() )
00144     // no remote blackboard opened, yet
00145   {
00146     try
00147     {
00148       rbb = new RemoteBlackBoard( h, 1910 );
00149       m_remote_bbs[ host ] = rbb;
00150     }
00151     catch ( Exception& e )
00152     {
00153       e.append( "Could not open remote blackboard on host %s", h );
00154       e.print_trace();
00155       return;
00156     }
00157   }
00158   else
00159   { rbb = i->second; }
00160
00161   if ( m_battery_interfaces.find( host ) == m_battery_interfaces.end() )
00162     // no battery interface opened, yet
00163   {
00164     try
00165     {
00166       BatteryInterface* bi;
00167       bi = rbb->open_for_reading< BatteryInterface >( "Battery" );
00168       m_battery_interfaces[ host ] = bi;
00169
00170       InterfaceDispatcher* id = new InterfaceDispatcher( "BatteryMonitorTreeView", bi );
00171
00172       id->signal_data_changed().connect( sigc::mem_fun( *this,
00173                                                         &BatteryMonitorTreeView::on_data_changed ) );
00174       id->signal_writer_added().connect( sigc::mem_fun( *this,
00175                                                         &BatteryMonitorTreeView::on_writer_added ) );
00176       id->signal_writer_removed().connect( sigc::mem_fun( *this,
00177                                                           &BatteryMonitorTreeView::on_writer_removed ) );
00178       rbb->register_listener( id, BlackBoard::BBIL_FLAG_DATA || BlackBoard::BBIL_FLAG_WRITER );
00179     }
00180     catch ( Exception& e )
00181     {
00182       e.append( "Opening battery interface on host %s failed", h );
00183       e.print_trace();
00184     }
00185
00186     // add below threshold counter
00187     m_below_threshold_counter[ host ] = 0;
00188   }
00189
00190   m_trigger_update();
00191 }
00192 
00193 /** Remove given host.
00194  * @param h the host's hostname
00195  */
00196 void
00197 BatteryMonitorTreeView::rem_host( const char* h )
00198 {
00199   string host( h );
00200
00201   std::map< string, BlackBoard* >::iterator rbbit = m_remote_bbs.find( host );
00202   if ( m_remote_bbs.end() == rbbit )
00203     // no blackboard opened---nothing to do
00204   { return; }
00205
00206   std::map< string, BatteryInterface* >::iterator biit = m_battery_interfaces.find( host );
00207
00208   if ( m_battery_interfaces.end() != biit )
00209     // battery inteface opened. listener need to be unregistered and
00210     // interface nees to be closed
00211   {
00212     try
00213     {
00214       BlackBoard* rbb = rbbit->second;
00215       InterfaceDispatcher* id = m_interface_dispatcher.find( host )->second;
00216       rbb->unregister_listener( id );
00217       rbb->close( biit->second );
00218       m_battery_interfaces.erase( biit );
00219     }
00220     catch ( Exception& e )
00221     {
00222       e.append( "Closing battery interface for host %s could not be closed", h );
00223       e.print_trace();
00224     }
00225   }
00226
00227   // destroy blackboard
00228   delete rbbit->second;
00229   m_remote_bbs.erase( rbbit );
00230
00231   // remove below threshold counter
00232   m_below_threshold_counter.erase( host );
00233
00234   m_trigger_update();
00235 }
00236
00237 void
00238 BatteryMonitorTreeView::update()
00239 {
00240   // clear treeview
00241   Gtk::TreeModel::Children::iterator rit = m_battery_list->children().begin();
00242   while ( rit != m_battery_list->children().end() )
00243   {
00244     rit = m_battery_list->erase( rit );
00245   }
00246
00247   for ( std::map< string, BatteryInterface* >::iterator biit = m_battery_interfaces.begin();
00248         biit != m_battery_interfaces.end();
00249         ++biit )
00250   {
00251     // update data in interface
00252     BatteryInterface* bi = biit->second;
00253
00254     try
00255     {
00256       bi->read();
00257     }
00258     catch ( Exception& e )
00259     {
00260       e.append( "read() failed" );
00261       e.print_trace();
00262       continue;
00263     }
00264
00265     if ( !bi->has_writer() )
00266       // only consider interfaces which have a writer
00267     { continue; }
00268
00269     Gtk::TreeModel::Row row;
00270     row = *m_battery_list->append();
00271     row[ m_battery_record.fqdn ] = Glib::ustring( biit->first );
00272
00273     char* fqdn = strdup( (biit->first).c_str() );
00274     char* sh;
00275     char delim = '.';
00276     sh = strtok( fqdn, &delim );
00277     int i = atoi( sh );
00278
00279     if ( 0 != i )
00280     { row[ m_battery_record.short_name ] = Glib::ustring( biit->first ); }
00281     else
00282     { row[ m_battery_record.short_name ] = Glib::ustring( sh ); }
00283
00284     row[ m_battery_record.absolute_soc ] = bi->absolute_soc() * 100.0;
00285     row[ m_battery_record.relative_soc ] = bi->relative_soc() * 100.0;
00286     row[ m_battery_record.current ] = bi->current() / 1000.0;
00287     row[ m_battery_record.voltage ] = bi->voltage() / 1000.0;
00288
00289     string fqdn_str = string( fqdn );
00290     if ( row[ m_battery_record.relative_soc ] <= m_relative_soc_threshold )
00291     {
00292       unsigned int cnt = m_below_threshold_counter[ fqdn_str ];
00293       m_below_threshold_counter[ fqdn_str ] = ++cnt;
00294     }
00295     else
00296     { m_below_threshold_counter[ fqdn_str ] = 0; }
00297
00298     free(fqdn);
00299   }
00300
00301   Glib::ustring secondary = "The batteries on ";
00302   bool below_threshold = false;
00303
00304   for ( std::map< string, unsigned int >::iterator i = m_below_threshold_counter.begin();
00305         i != m_below_threshold_counter.end();
00306         ++i )
00307   {
00308     if ( i->second > 2 )
00309     {
00310       secondary += "<b>" + Glib::ustring( (i->first).c_str() ) + "</b>" + " ";
00311       i->second = 0;
00312
00313       below_threshold = true;
00314     }
00315   }
00316   secondary += "need to be replaced.";
00317
00318   if ( below_threshold )
00319   {
00320     m_dlg_warning->set_secondary_text( secondary, true );
00321     m_dlg_warning->set_urgency_hint();
00322     m_dlg_warning->run();
00323     m_dlg_warning->hide();
00324   }
00325 }
00326
00327 void
00328 BatteryMonitorTreeView::on_data_changed( fawkes::Interface* interface )
00329 {
00330   update();
00331 }
00332
00333 void
00334 BatteryMonitorTreeView::on_writer_added( fawkes::Interface* interface )
00335 {
00336   update();
00337 }
00338
00339 void
00340 BatteryMonitorTreeView::on_writer_removed( fawkes::Interface* interface )
00341 {
00342   update();
00343 }