Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * eclipse_thread.cpp - Fawkes Readylog ECLiPSe Thread 00004 * 00005 * Created: Wed Jul 16 10:42:49 2009 00006 * Copyright 2009 Daniel Beck 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include "eclipse_thread.h" 00024 #include "externals/fawkes_bb_interface.h" 00025 #include "externals/fawkes_logger.h" 00026 00027 #include <interfaces/TestInterface.h> 00028 #include <core/exception.h> 00029 00030 #include <eclipseclass.h> 00031 00032 #include <cstdio> 00033 #include <cstdlib> 00034 #include <cstring> 00035 #include <vector> 00036 00037 using namespace std; 00038 using namespace fawkes; 00039 00040 /** @class EclipseAgentThread "eclipse_thread.h" 00041 * This thread creates an ECLiPSe context in which the Readylog 00042 * interpreter and the program are loaded. 00043 * @author Daniel Beck 00044 */ 00045 00046 extern "C" int ec_external( dident, int (*) (), dident ); 00047 00048 EclipseAgentThread* EclipseAgentThread::m_instance = NULL; 00049 00050 /** Constructor. */ 00051 EclipseAgentThread::EclipseAgentThread() 00052 : Thread( "ECLiPSe thread", fawkes::Thread::OPMODE_CONTINUOUS ), 00053 m_initialized( false ) 00054 { 00055 m_instance = this; 00056 } 00057 00058 /** Destructor. */ 00059 EclipseAgentThread::~EclipseAgentThread() 00060 { 00061 } 00062 00063 void 00064 EclipseAgentThread::init() 00065 { 00066 // set ECLiPSe installation directory 00067 char* eclipse_dir = NULL; 00068 try 00069 { 00070 eclipse_dir = strdup( config->get_string( "/readylogagent/eclipse_dir" ).c_str() ); 00071 logger->log_info( name(), "Setting ECLIPSEDIR to %s", eclipse_dir ); 00072 ec_set_option_ptr( EC_OPTION_ECLIPSEDIR, (void*) eclipse_dir ); 00073 } 00074 catch (...) 00075 { 00076 // ignore 00077 } 00078 00079 // initialize ECLiPSe context 00080 if ( 0 != ec_init() ) 00081 { throw fawkes::Exception( "Failed to initialize ECLiPSe context" ); } 00082 00083 free( eclipse_dir ); 00084 00085 // register external predicates 00086 if ( EC_succeed != ec_external( ec_did( "read_interface", 2 ), p_read_interface, ec_did( "eclipse", 0 ) ) ) 00087 { throw Exception( "Registering external predicate read_interface/2 failed" ); } 00088 if ( EC_succeed != ec_external( ec_did( "write_interface", 2 ), p_write_interface, ec_did( "eclipse", 0 ) ) ) 00089 { throw Exception( "Registering external predicate write_interface/2 failed" ); } 00090 if ( EC_succeed != ec_external( ec_did( "send_message", 2 ), p_send_message, ec_did( "eclipse", 0 ) ) ) 00091 { throw Exception( "Registering external predicate send_message/2 failed" ); } 00092 if ( EC_succeed != ec_external( ec_did( "recv_messages", 2 ), p_recv_messages, ec_did( "eclipse", 0 ) ) ) 00093 { throw Exception( "Registering external predicate recv_messages/2 failed" ); } 00094 if ( EC_succeed != ec_external( ec_did( "log", 2 ), p_log, ec_did( "eclipse", 0 ) ) ) 00095 { throw Exception( "Registering external predicate log/2 failed" ); } 00096 00097 m_initialized = true; 00098 00099 // open & register interfaces 00100 try 00101 { 00102 // open for interfaces reading 00103 Configuration::ValueIterator* vit = config->search( "/readylogagent/interfaces/reading" ); 00104 while ( vit->next() ) 00105 { 00106 if ( vit->is_string() ) 00107 { 00108 string s = vit->get_string(); 00109 if ( s.find("::") == string::npos ) 00110 { throw Exception( "Not a valid interface id: %s", s.c_str() ); } 00111 00112 string iftype = s.substr( 0, s.find( "::" ) ); 00113 string ifname = s.substr( s.find( "::" ) + 2 ); 00114 00115 logger->log_debug( name(), "Opening interface %s of type %s for reading", 00116 ifname.c_str(), iftype.c_str() ); 00117 00118 Interface* iface = blackboard->open_for_reading( iftype.c_str(), ifname.c_str() ); 00119 m_reading_ifaces.push_back( iface ); 00120 register_interface( iface ); 00121 } 00122 } 00123 00124 // open interfaces for writing 00125 vit = config->search( "/readylogagent/interfaces/writing" ); 00126 while ( vit->next() ) 00127 { 00128 if ( vit->is_string() ) 00129 { 00130 string s = vit->get_string(); 00131 if ( s.find("::") == string::npos ) 00132 { throw Exception( "Not a valid interface id: %s", s.c_str() ); } 00133 00134 string iftype = s.substr( 0, s.find( "::" ) ); 00135 string ifname = s.substr( s.find( "::" ) + 2 ); 00136 00137 logger->log_debug( name(), "Opening interface %s of type %s for writing", 00138 ifname.c_str(), iftype.c_str() ); 00139 00140 Interface* iface = blackboard->open_for_writing( iftype.c_str(), ifname.c_str() ); 00141 m_writing_ifaces.push_back( iface ); 00142 register_interface( iface ); 00143 } 00144 } 00145 } 00146 catch ( Exception& e ) 00147 { 00148 e.append( "Failed to open interfaces" ); 00149 throw e; 00150 } 00151 00152 // load utility predicates 00153 load_file( ECLIPSE_CODE_DIR"/utils/logging.ecl" ); 00154 00155 // load interpreter and agent 00156 load_file( ECLIPSE_CODE_DIR"/interpreter/dummy.ecl" ); 00157 } 00158 00159 void 00160 EclipseAgentThread::finalize() 00161 { 00162 ec_cleanup(); 00163 } 00164 00165 void 00166 EclipseAgentThread::once() 00167 { 00168 post_goal( "run" ); 00169 if ( EC_succeed != EC_resume() ) 00170 { throw Exception( "Error running agent program" ); } 00171 } 00172 00173 /** Post an event to the ECLiPSe context. 00174 * @param event the name of the event 00175 */ 00176 void 00177 EclipseAgentThread::post_event( const char* event ) 00178 { 00179 if ( !m_initialized ) { return; } 00180 00181 // send event to the interpreter 00182 char* atom = strdup( event ); 00183 ::post_event( EC_atom( atom ) ); 00184 free( atom ); 00185 } 00186 00187 /** Read all registered interfaces. */ 00188 void 00189 EclipseAgentThread::read_interfaces() 00190 { 00191 for ( vector< Interface* >::iterator i = m_reading_ifaces.begin(); 00192 i != m_reading_ifaces.end(); 00193 ++i ) 00194 { (*i)->read(); } 00195 00196 for ( vector< Interface* >::iterator i = m_writing_ifaces.begin(); 00197 i != m_writing_ifaces.end(); 00198 ++i ) 00199 { (*i)->read(); } 00200 } 00201 00202 /** Write the registered interface that have been opened for writing. */ 00203 void 00204 EclipseAgentThread::write_interfaces() 00205 { 00206 for ( vector< Interface* >::iterator i = m_writing_ifaces.begin(); 00207 i != m_writing_ifaces.end(); 00208 ++i ) 00209 { (*i)->write(); } 00210 } 00211 00212 /** Load a file into the ECLiPSe context. 00213 * @param filename the name of the file 00214 * @return false if the ECLiPSe context hasn't been intialized yet 00215 */ 00216 bool 00217 EclipseAgentThread::load_file( const char* filename ) 00218 { 00219 if ( !m_initialized ) { return false; } 00220 00221 char* ensure_loaded = strdup( "ensure_loaded" ); 00222 post_goal( term( EC_functor( ensure_loaded, 1 ), filename ) ); 00223 free( ensure_loaded ); 00224 00225 if ( EC_succeed != ec_resume() ) 00226 { throw Exception( "File %s could not be loaded", filename ); } 00227 00228 return true; 00229 } 00230 00231 /** Register an interface for access from within the ECLiPSe context. 00232 * @param interface the interface to register 00233 * @return false if the ECLiPSe context hasn't been intialized yet 00234 */ 00235 bool 00236 EclipseAgentThread::register_interface( fawkes::Interface* interface ) 00237 { 00238 if ( !m_initialized ) { return false; } 00239 00240 m_registered_interfaces[ string( interface->id() ) ] = interface; 00241 00242 00243 // define structs for interface data ---------------------------------- 00244 // data_IntefaceType(field1, field2, ...) ----------------------------- 00245 00246 // check whether struct is already defined 00247 char* struct_name; 00248 asprintf( &struct_name, "data_%s", interface->type() ); 00249 00250 post_goal( term( EC_functor( (char *) "current_struct", 2 ), 00251 EC_atom( struct_name ), 00252 newvar() ) ); 00253 00254 if ( EC_succeed != ec_resume() ) 00255 { 00256 // define named structure 00257 // data_InterfaceType( field1, field2, ... ) 00258 00259 vector< string > fields; 00260 for ( InterfaceFieldIterator i = interface->fields(); 00261 i != interface->fields_end(); 00262 ++i ) 00263 { fields.push_back( i.get_name() ); } 00264 00265 EC_word args[ fields.size() ]; 00266 00267 for ( size_t i = 0 ; i < fields.size(); ++i ) 00268 { 00269 char* c = strdup( fields.at( i ).c_str() ); 00270 args[ i ] = EC_atom( c ); 00271 free( c ); 00272 } 00273 00274 EC_word new_struct = term( EC_functor( struct_name, (int) fields.size() ), args ); 00275 00276 char* local = strdup( "local" ); 00277 char* strct = strdup( "struct" ); 00278 EC_word struct_def = term( EC_functor( strct, 1 ), new_struct ); 00279 EC_word struct_def_local = term( EC_functor( local, 1), struct_def ); 00280 00281 char* call = strdup( "call" ); 00282 // call( struct( data_InterfaceType(field1, field2, ...) ) ) 00283 post_goal( term( EC_functor( call, 1 ), struct_def_local ) ); 00284 00285 // cleanup 00286 free( local ); 00287 free( strct ); 00288 free( call ); 00289 00290 if ( EC_succeed != ec_resume() ) 00291 { throw Exception( "Failed to define structure %s", struct_name ); } 00292 } 00293 00294 free( struct_name ); 00295 00296 00297 // define structs for message data ------------------------------------ 00298 // data_IntefaceType_MessageType(field1, field2, ...) ----------------- 00299 00300 std::list<const char *> message_types = interface->get_message_types(); 00301 for ( std::list<const char *>::iterator type_iter = message_types.begin(); 00302 type_iter != message_types.end(); 00303 ++type_iter ) 00304 { 00305 // check whether struct is already defined 00306 char* struct_name; 00307 asprintf( &struct_name, "data_%s_%s", interface->type(), *type_iter ); 00308 00309 post_goal( term( EC_functor( (char *) "current_struct", 2 ), 00310 EC_atom( struct_name ), 00311 newvar() ) ); 00312 00313 if ( EC_succeed != ec_resume() ) 00314 { 00315 // define name structure 00316 // data_InterfaceType_MessageType( field1, field2, ... ) 00317 00318 Message* msg = interface->create_message( *type_iter ); 00319 00320 vector< string > fields; 00321 for ( InterfaceFieldIterator field_iter = msg->fields(); 00322 field_iter != msg->fields_end(); 00323 ++field_iter ) 00324 { 00325 string name = field_iter.get_name(); 00326 fields.push_back( name ); 00327 } 00328 00329 delete msg; 00330 00331 EC_word args[ fields.size() ]; 00332 00333 for ( size_t i = 0; i < fields.size(); ++i ) 00334 { 00335 char* c = strdup( fields.at( i ).c_str() ); 00336 args[ i ] = EC_atom( c ); 00337 free( c ); 00338 } 00339 00340 if ( 0 != fields.size() ) 00341 { 00342 EC_word new_struct = term( EC_functor( struct_name, (int) fields.size() ), args ); 00343 char* local = strdup( "local" ); 00344 char* strct = strdup( "struct" ); 00345 EC_word struct_def = term( EC_functor( strct, 1 ), new_struct ); 00346 EC_word struct_def_local = term( EC_functor( local, 1), struct_def ); 00347 00348 char* call = strdup( "call" ); 00349 // call( struct( data_InterfaceType_MessageType(field1, field2, ...) ) ) 00350 post_goal( term( EC_functor( call, 1 ), struct_def_local ) ); 00351 00352 // cleanup 00353 free( local ); 00354 free( strct ); 00355 free( call ); 00356 00357 if ( EC_succeed != ec_resume() ) 00358 { throw Exception( "Failed to define structure %s", struct_name ); } 00359 } 00360 } 00361 00362 free( struct_name ); 00363 } 00364 00365 return true; 00366 } 00367 00368 /** Get the registered interface with the given id. 00369 * @param id the interface id 00370 * @return the interface or NULL if no interface with the given id is registerd 00371 */ 00372 fawkes::Interface* 00373 EclipseAgentThread::get_registered_interface( const char* id ) 00374 { 00375 map< string, fawkes::Interface* >::iterator i = m_registered_interfaces.find( string( id ) ); 00376 00377 if ( i == m_registered_interfaces.end() ) { return NULL; } 00378 00379 return i->second; 00380 } 00381 00382 /** Get the logger. 00383 * @return the logger 00384 */ 00385 fawkes::Logger* 00386 EclipseAgentThread::get_logger() 00387 { 00388 return logger; 00389 } 00390 00391 /** Get the EclipseAgentThread instance. 00392 * @return the instance 00393 */ 00394 EclipseAgentThread* 00395 EclipseAgentThread::instance() 00396 { 00397 if ( !m_instance ) 00398 { throw Exception( "No instance of type EclipseThread instantiated" ); } 00399 00400 return m_instance; 00401 }