Fawkes API  Fawkes Development Version
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 <interfaces/BatteryInterface.h>
00029 
00030 #include <cstring>
00031 
00032 using namespace std;
00033 using namespace fawkes;
00034 
00035 /** @class BatteryMonitorTreeView tools/battery_monitor/battery_monitor_treeview.h
00036  * A treeview that retrieves battery data from the robots over remote
00037  * blackboard connections and displays those.
00038  * @author Daniel Beck
00039  */
00040 
00041 /** @class BatteryMonitorTreeView::BatteryRecord tools/battery_monitor/battery_monitor_treeview.h
00042  * Column record class for the battery monitor treeview.
00043  * @author Daniel Beck
00044  */
00045 
00046 /** @var BatteryMonitorTreeView::m_battery_record
00047  * Column record object to acces the columns of the storage object.
00048  */
00049 
00050 /** @var BatteryMonitorTreeView::m_battery_list
00051  * Storage object.
00052  */
00053 
00054 /** @var BatteryMonitorTreeView::m_remote_bbs
00055  * Map with remote blackboards: hostname -> remote blackboard.
00056  */
00057 
00058 /** @var BatteryMonitorTreeView::m_battery_interfaces
00059  * Map containing the battery interfaces: hostname -> battery interface
00060  */
00061 
00062 /** @var BatteryMonitorTreeView::m_interface_dispatcher
00063  * Interface dispatcher for the battery interfaces.
00064  */
00065 
00066 /** Constructor.
00067  * @param cobject base object type
00068  * @param builder builder to get widgets from
00069  */
00070 BatteryMonitorTreeView::BatteryMonitorTreeView(BaseObjectType* cobject,
00071                                                const Glib::RefPtr<Gtk::Builder> &builder)
00072   : Gtk::TreeView( cobject )
00073 {
00074   m_battery_list = Gtk::ListStore::create( m_battery_record );
00075   set_model( m_battery_list );
00076 
00077   append_column( "Host", m_battery_record.short_name );
00078   append_column_numeric( "Abs. SOC [%]", m_battery_record.absolute_soc, "%.1f" ); 
00079   append_column_numeric( "Rel. SOC [%]", m_battery_record.relative_soc, "%.1f" ); 
00080   append_column_numeric( "Voltage [V]", m_battery_record.voltage, "%.3f" );
00081   append_column_numeric( "Current [A]", m_battery_record.current, "%.3f" );
00082 
00083   builder->get_widget("dlgWarning", m_dlg_warning);
00084   m_dlg_warning->hide();
00085 
00086   m_trigger_update.connect(sigc::mem_fun(*this, &BatteryMonitorTreeView::update));
00087 
00088   m_relative_soc_threshold = 20.0;
00089 }
00090 
00091 /** Destructor. */
00092 BatteryMonitorTreeView::~BatteryMonitorTreeView()
00093 {
00094   std::map< string, BatteryInterface* >::iterator biit;
00095   for (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   std::map< string, InterfaceDispatcher* >::iterator i;
00115   for (i = m_interface_dispatcher.begin();
00116        i != m_interface_dispatcher.end();
00117        ++i )
00118   {
00119     delete i->second;
00120   }
00121 
00122   // delete remote blackboards
00123   for ( std::map< string, BlackBoard* >::iterator i = m_remote_bbs.begin();
00124         i != m_remote_bbs.end();
00125         ++i )
00126   {
00127     delete i->second;
00128   }
00129 
00130   delete m_dlg_warning;
00131 }
00132 
00133 /** Add given host.
00134  * @param h the host's hostname
00135  */
00136 void
00137 BatteryMonitorTreeView::add_host( const char* h )
00138 {
00139   string host(h);
00140 
00141   BlackBoard* rbb;
00142   std::map< string, BlackBoard* >::iterator i = m_remote_bbs.find( host );
00143 
00144   if ( i == m_remote_bbs.end() )
00145     // no remote blackboard opened, yet
00146   {
00147     try
00148     { 
00149       rbb = new RemoteBlackBoard( h, 1910 );
00150       m_remote_bbs[ host ] = rbb;
00151     }
00152     catch ( Exception& e )
00153     {
00154       e.append( "Could not open remote blackboard on host %s", h );
00155       e.print_trace();
00156       return;
00157     }
00158   }
00159   else
00160   { rbb = i->second; }
00161 
00162   if ( m_battery_interfaces.find( host ) == m_battery_interfaces.end() )
00163     // no battery interface opened, yet
00164   {
00165     try
00166     {
00167       BatteryInterface* bi;
00168       bi = rbb->open_for_reading< BatteryInterface >( "Battery" );
00169       m_battery_interfaces[ host ] = bi;
00170 
00171       InterfaceDispatcher* id =
00172         new InterfaceDispatcher( "BatteryMonitorTreeView", bi );
00173 
00174       id->signal_data_changed().connect( sigc::mem_fun( *this,
00175                                                         &BatteryMonitorTreeView::on_data_changed ) );
00176       id->signal_writer_added().connect( sigc::mem_fun( *this,
00177                                                         &BatteryMonitorTreeView::on_writer_added ) );
00178       id->signal_writer_removed().connect( sigc::mem_fun( *this,
00179                                                           &BatteryMonitorTreeView::on_writer_removed ) );
00180       rbb->register_listener( id, BlackBoard::BBIL_FLAG_DATA | BlackBoard::BBIL_FLAG_WRITER );
00181     }
00182     catch ( Exception& e )
00183     {
00184       e.append( "Opening battery interface on host %s failed", h );
00185       e.print_trace();
00186     }
00187 
00188     // add below threshold counter
00189     m_below_threshold_counter[ host ] = 0;
00190   }
00191   
00192   m_trigger_update();
00193 }
00194 
00195 /** Remove given host.
00196  * @param h the host's hostname
00197  */
00198 void
00199 BatteryMonitorTreeView::rem_host( const char* h )
00200 {
00201   string host( h );
00202 
00203   std::map< string, BlackBoard* >::iterator rbbit = m_remote_bbs.find( host );
00204   if ( m_remote_bbs.end() == rbbit )
00205     // no blackboard opened---nothing to do
00206   { return; }
00207 
00208   std::map< string, BatteryInterface* >::iterator biit = m_battery_interfaces.find( host );
00209 
00210   if ( m_battery_interfaces.end() != biit )
00211     // battery inteface opened. listener need to be unregistered and
00212     // interface nees to be closed
00213   {
00214     try
00215     {
00216       BlackBoard* rbb = rbbit->second;
00217       InterfaceDispatcher* id = m_interface_dispatcher.find( host )->second;
00218       rbb->unregister_listener( id );
00219       rbb->close( biit->second );
00220       m_battery_interfaces.erase( biit );
00221     }
00222     catch ( Exception& e )
00223     {
00224       e.append( "Closing battery interface for host %s could not be closed", h );
00225       e.print_trace();
00226     }
00227   }
00228 
00229   // destroy blackboard
00230   delete rbbit->second;
00231   m_remote_bbs.erase( rbbit );
00232 
00233   // remove below threshold counter
00234   m_below_threshold_counter.erase( host );
00235 
00236   m_trigger_update();
00237 }
00238 
00239 void
00240 BatteryMonitorTreeView::update()
00241 {
00242   // clear treeview
00243   Gtk::TreeModel::Children::iterator rit = m_battery_list->children().begin();
00244   while ( rit != m_battery_list->children().end() )
00245   {
00246     rit = m_battery_list->erase( rit );
00247   }
00248 
00249   for ( std::map< string, BatteryInterface* >::iterator biit = m_battery_interfaces.begin();
00250         biit != m_battery_interfaces.end();
00251         ++biit )
00252   {
00253     // update data in interface
00254     BatteryInterface* bi = biit->second;
00255 
00256     try
00257     {
00258       bi->read();
00259     }
00260     catch ( Exception& e )
00261     {
00262       e.append( "read() failed" );
00263       e.print_trace();
00264       continue;
00265     }
00266 
00267     if ( !bi->has_writer() )
00268       // only consider interfaces which have a writer
00269     { continue; }
00270 
00271     Gtk::TreeModel::Row row;
00272     row = *m_battery_list->append();
00273     row[ m_battery_record.fqdn ] = Glib::ustring( biit->first );
00274     
00275     char* fqdn = strdup( (biit->first).c_str() );
00276     char* sh;
00277     char delim = '.';
00278     sh = strtok( fqdn, &delim );
00279     int i = atoi( sh );
00280     
00281     if ( 0 != i )
00282     { row[ m_battery_record.short_name ] = Glib::ustring( biit->first ); }
00283     else
00284     { row[ m_battery_record.short_name ] = Glib::ustring( sh ); }
00285     
00286     row[ m_battery_record.absolute_soc ] = bi->absolute_soc() * 100.0;
00287     row[ m_battery_record.relative_soc ] = bi->relative_soc() * 100.0;
00288     row[ m_battery_record.current ] = bi->current() / 1000.0;
00289     row[ m_battery_record.voltage ] = bi->voltage() / 1000.0;
00290 
00291     string fqdn_str = string( fqdn );
00292     if ( row[ m_battery_record.relative_soc ] <= m_relative_soc_threshold )
00293     {
00294       unsigned int cnt = m_below_threshold_counter[ fqdn_str ];
00295       m_below_threshold_counter[ fqdn_str ] = ++cnt;
00296     }
00297     else
00298     { m_below_threshold_counter[ fqdn_str ] = 0; }
00299 
00300     free(fqdn);
00301   }
00302   
00303   Glib::ustring secondary = "The batteries on ";
00304   bool below_threshold = false;
00305 
00306   for ( std::map< string, unsigned int >::iterator i = m_below_threshold_counter.begin();
00307         i != m_below_threshold_counter.end();
00308         ++i )
00309   {
00310     if ( i->second > 2 )
00311     {
00312       secondary += "<b>" + Glib::ustring( (i->first).c_str() ) + "</b>" + " ";
00313       i->second = 0;
00314 
00315       below_threshold = true;
00316     }
00317   }
00318   secondary += "need to be replaced.";
00319 
00320   if ( below_threshold )
00321   {
00322     m_dlg_warning->set_secondary_text( secondary, true );
00323     m_dlg_warning->set_urgency_hint();
00324     m_dlg_warning->run();
00325     m_dlg_warning->hide();
00326   }
00327 }
00328 
00329 void
00330 BatteryMonitorTreeView::on_data_changed( fawkes::Interface* interface )
00331 {
00332   update();
00333 }
00334 
00335 void
00336 BatteryMonitorTreeView::on_writer_added( fawkes::Interface* interface )
00337 {
00338   update();
00339 }
00340 
00341 void
00342 BatteryMonitorTreeView::on_writer_removed( fawkes::Interface* interface )
00343 {
00344   update();
00345 }