fawkes_bb_interface.cpp

00001
00002 /***************************************************************************
00003  *  fawkes_bb_interface.h - External predicates to access Fawkes interfaces
00004  *
00005  *  Created: Wed Jul 15 16:20:04 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 "fawkes_bb_interface.h"
00024 #include <plugins/readylogagent/eclipse_thread.h>
00025
00026 #include <core/exceptions/software.h>
00027 #include <interface/interface.h>
00028 #include <interfaces/ObjectPositionInterface.h>
00029
00030 #include <eclipseclass.h>
00031
00032 #include <cstdlib>
00033 #include <cstring>
00034 #include <map>
00035 #include <string>
00036 #include <list>
00037
00038 using namespace std;
00039 using namespace fawkes;
00040
00041 EC_word  construct_iface_struct( Interface* iface );
00042 EC_word  construct_msg_struct( const char* iface_type, Message* msg );
00043 EC_word* construct_struct_args( const InterfaceFieldIterator& begin,
00044                                 const InterfaceFieldIterator& end,
00045                                 unsigned int num_fields );
00046 void parse_struct_args( EC_word iface_struct,
00047                         const InterfaceFieldIterator& begin,
00048                         const InterfaceFieldIterator& end,
00049                         unsigned int num_fields );
00050
00051 int
00052 p_read_interface()
00053 {
00054   // read_interface(+IdStr, -DataStruct)
00055   // DataStruct is bound to a struct with named elements. The name of
00056   // that struct is data_InterfaceType, the fields are named in the
00057   // same way as the fields of the interface.
00058
00059   // check if interface with given id is available
00060   Interface* interface;
00061   char* id;
00062
00063   // get interface id
00064   if ( EC_succeed != EC_arg( 1 ).is_string( &id ) )
00065   {
00066     printf( "First argument of read_interface/2 is not a string\n" );
00067     return EC_fail;
00068   }
00069
00070   // get interface
00071   interface = EclipseAgentThread::instance()->get_registered_interface( id );
00072   if ( !interface )
00073   {
00074     printf( "Interface with id %s is not available to the agent\n", id );
00075     return EC_fail;
00076   }
00077
00078   // construct data structure
00079   EC_word iface_struct;
00080   try
00081   {
00082     iface_struct = construct_iface_struct( interface );
00083   }
00084   catch ( Exception& e )
00085   {
00086     e.print_trace();
00087     return EC_fail;
00088   }
00089
00090   // bind 2nd argument
00091   return unify( EC_arg(2), iface_struct );
00092 }
00093
00094 int
00095 p_write_interface()
00096 {
00097   // write_interface(+IdStr, +DataStruct)
00098   // The structure passed as the second argument has to be of type
00099   // data_InterfaceType such that the interface type matches the type
00100   // of the interface with the given id.
00101
00102   char* id;
00103   Interface* interface;
00104
00105   // get interface id
00106   if ( EC_succeed != EC_arg( 1 ).is_string( &id ) )
00107   {
00108     printf( "Firste argument of write_interface/2 is not a string\n" );
00109     return EC_fail;
00110   }
00111
00112   // get interface
00113   interface = EclipseAgentThread::instance()->get_registered_interface( id );
00114   if ( !interface )
00115   {
00116     printf( "Interface with id %s is not available to the agent\n", id );
00117     return EC_fail;
00118   }
00119
00120   // get functor of 2nd argument
00121   EC_functor fctor;
00122   if ( EC_succeed != EC_arg( 2 ).functor( &fctor ) )
00123   {
00124     printf( "Second argument of writer_interface/2 is not a compound term\n" );
00125     return EC_fail;
00126   }
00127
00128   // check interface type
00129   char* iface_type;
00130   if ( 1 != sscanf( fctor.name(), "data_%s", iface_type ) ||
00131        0 != strcmp( interface->type(), iface_type ) )
00132   {
00133     printf( "Second argument of write_interface/2 is not of type data_%s but of type %s\n",
00134             interface->type(), fctor.name() );
00135     free( iface_type );
00136     return EC_fail;
00137   }
00138   free( iface_type );
00139
00140   // check arity
00141   unsigned int arity = (unsigned int) EC_arg( 2 ).arity();
00142   if ( interface->num_fields() != arity )
00143   {
00144     printf( "Second argument of write_interface/2 has wrong arity\n" );
00145     return EC_fail;
00146   }
00147
00148   // copy data
00149   try
00150   {
00151     parse_struct_args( EC_word( 2 ),
00152                        interface->fields(),
00153                        interface->fields_end(),
00154                        interface->num_fields() );
00155   }
00156   catch ( Exception& e )
00157   {
00158     e.print_trace();
00159     return EC_fail;
00160   }
00161
00162   return EC_succeed;
00163 }
00164
00165 int
00166 p_send_message()
00167 {
00168   // send_message(id, data_InterfaceType_MessageType{key1:param1, ...})
00169
00170   // check if interface with given id is available
00171   char* iface_id;
00172   Interface* interface;
00173
00174   // get interface id
00175   if ( EC_succeed != EC_arg( 1 ).is_string( &iface_id ) )
00176   {
00177     printf( "First argument of send_message/2 is not an atom\n" );
00178     return EC_fail;
00179   }
00180
00181   // get interface
00182   interface = EclipseAgentThread::instance()->get_registered_interface( iface_id );
00183   if ( !interface )
00184   {
00185     printf( "Interface with id %s is not available to the agent\n", iface_id );
00186     return EC_fail;
00187   }
00188
00189   // check functor of 2nd argument
00190   EC_functor fctor;
00191   if ( EC_succeed != EC_arg( 2 ).functor( &fctor ) )
00192   {
00193     printf( "Second argument of send_message/2 has no functor\n" );
00194     return EC_fail;
00195   }
00196
00197   char* fctor_name = strdup( fctor.name() );
00198   strtok( fctor_name, "_" );
00199   char* iface_type = strtok( NULL, "_" );
00200   char* msg_type = strtok( NULL, "_" );
00201
00202   if ( !iface_type ||
00203        !msg_type   ||
00204        0 != strcmp( interface->type(), iface_type )  )
00205   {
00206     printf( "Malformed functor: %s\n", fctor.name() );
00207     return EC_fail;
00208   }
00209
00210   // create message of given type
00211   Message* msg;
00212   try
00213   {
00214     msg = interface->create_message( msg_type );
00215   }
00216   catch ( UnknownTypeException& e )
00217   {
00218     printf( "Message type %s is not available for interfaces of type %s\n",
00219             msg_type, interface->type() );
00220     return EC_fail;
00221   }
00222
00223   // cleanup
00224   free( fctor_name );
00225
00226   // parse parameters
00227   try
00228   {
00229     parse_struct_args( EC_arg( 2 ), msg->fields(), msg->fields_end(), msg->num_fields() );
00230   }
00231   catch ( Exception& e )
00232   {
00233     e.print_trace();
00234     return EC_fail;
00235   }
00236
00237   // enqueue message
00238   interface->msgq_enqueue( msg );
00239
00240   return EC_succeed;
00241 }
00242
00243 int
00244 p_recv_messages()
00245 {
00246   // recv_messages( +IdStr, -MsgList )
00247   // MsgList is a list of message type structurs. The last message in
00248   // the list is the most recent one.
00249
00250   // check if interface with given id is available
00251   char* iface_id;
00252   Interface* interface;
00253
00254   if ( EC_succeed != EC_arg( 1 ).is_string( &iface_id ) )
00255   {
00256     printf( "First argument of send_message/2 is not an atom\n" );
00257     return EC_fail;
00258   }
00259
00260   interface = EclipseAgentThread::instance()->get_registered_interface( iface_id );
00261   if ( !interface )
00262   {
00263     printf( "Interface with id %s is not available to the agent\n", iface_id );
00264     return EC_fail;
00265   }
00266
00267   std::list< EC_word > messages;
00268
00269   while ( !interface-> msgq_empty() )
00270   {
00271     Message* msg = interface->msgq_first();
00272     EC_word msg_struct;
00273
00274     try
00275     {
00276       msg_struct = construct_msg_struct( interface->type(), msg );
00277     }
00278     catch( Exception& e )
00279     {
00280       e.print_trace();
00281       return EC_fail;
00282     }
00283
00284     messages.push_back( msg_struct );
00285
00286     interface->msgq_pop();
00287   }
00288
00289   EC_word l = nil();
00290   while( !messages.empty() )
00291   {
00292     l = ::list( messages.front(), l );
00293     messages.pop_front();
00294   }
00295
00296   return unify( EC_arg( 2 ), l );
00297 }
00298
00299 EC_word
00300 construct_iface_struct( Interface* iface )
00301 {
00302   EC_word* args = construct_struct_args( iface->fields(),
00303                                          iface->fields_end(),
00304                                          iface->num_fields() );
00305
00306   char* fctor;
00307   asprintf( &fctor, "data_%s", iface->type() );
00308
00309   EC_word ret = term( EC_functor( fctor, iface->num_fields() ), args );
00310
00311   delete[] args;
00312   free( fctor );
00313
00314   return ret;
00315 }
00316
00317 EC_word
00318 construct_msg_struct( const char* iface_type, Message* msg )
00319 {
00320   EC_word* args = construct_struct_args( msg->fields(), msg->fields_end(), msg->num_fields() );
00321
00322   char* fctor;
00323   asprintf( &fctor, "data_%s_%s", iface_type, msg->type() );
00324
00325   EC_word ret = term( EC_functor( fctor, msg->num_fields() ), args );
00326
00327   delete[] args;
00328   free( fctor );
00329
00330   return ret;
00331 }
00332
00333 EC_word*
00334 construct_struct_args( const InterfaceFieldIterator& begin,
00335                        const InterfaceFieldIterator& end,
00336                        unsigned int num_fields )
00337 {
00338   EC_word* args = new EC_word[ num_fields ];
00339
00340   InterfaceFieldIterator field_iter;
00341   unsigned int           field_idx;
00342   for ( field_iter = begin, field_idx = 0;
00343         field_iter != end;
00344         ++field_iter, ++field_idx )
00345   {
00346     interface_fieldtype_t type = field_iter.get_type();
00347
00348     switch ( type )
00349     {
00350     case IFT_BOOL: {
00351       char* t = strdup( "true" );
00352       char* f = strdup( "fail" );
00353
00354       args[ field_idx ] = field_iter.get_bool() ? EC_atom( t ) : EC_atom( f );
00355
00356       free( t );
00357       free( f );
00358
00359       break;
00360     }
00361
00362     case IFT_INT:
00363       args[ field_idx ] = EC_word( field_iter.get_int() );
00364       break;
00365
00366     case IFT_UINT:
00367       args[ field_idx ] = EC_word( (long) field_iter.get_uint() );
00368       break;
00369
00370     case IFT_LONGINT:
00371       args[ field_idx ] = EC_word( field_iter.get_longint() );
00372       break;
00373
00374     case IFT_LONGUINT:
00375       args[ field_idx ] = EC_word( (long) field_iter.get_longuint() );
00376       break;
00377
00378     case IFT_FLOAT:
00379       args[ field_idx ] = EC_word( field_iter.get_float() );
00380       break;
00381
00382     case IFT_STRING:
00383       args[ field_idx ] = EC_word( field_iter.get_string() );
00384       break;
00385
00386     case IFT_BYTE:
00387       args[ field_idx ] = EC_word( field_iter.get_byte() );
00388       break;
00389
00390     default:
00391       throw UnknownTypeException( "Field of unknown type %s", field_iter.get_typename() );
00392     }
00393   }
00394
00395   return args;
00396 }
00397
00398 void
00399 parse_struct_args( EC_word data_struct,
00400                    const InterfaceFieldIterator& begin,
00401                    const InterfaceFieldIterator& end,
00402                    unsigned int num_fields )
00403 {
00404   unsigned int           field_idx;
00405   InterfaceFieldIterator field_iter;
00406
00407   for ( field_iter = begin, field_idx = 1;
00408         field_iter != end;
00409         ++field_iter, ++field_idx )
00410   {
00411     interface_fieldtype_t type = field_iter.get_type();
00412
00413     EC_word arg;
00414     if ( EC_succeed != data_struct.arg( field_idx, arg ) )
00415     { throw Exception( "Failed to parse interface data. Couldn't read %d-th parameter.\n", field_idx ); }
00416
00417     switch( type )
00418     {
00419     case IFT_BOOL: {
00420       char* t = strdup( "true" );
00421       char* f = strdup( "fail" );
00422       if ( EC_succeed == arg.unify( EC_atom( t ) ) )
00423       { field_iter.set_bool( true ); }
00424       else if ( EC_succeed == arg.unify( EC_atom( f ) ) )
00425       { field_iter.set_bool( false ); }
00426       else
00427       {
00428         free( t );
00429         free( f );
00430         throw TypeMismatchException( "Wrong data type for %d-th argument\n", field_idx );
00431       }
00432
00433       free( t );
00434       free( f );
00435
00436       break;
00437     }
00438
00439     case IFT_INT: {
00440       long val;
00441       if ( EC_succeed == arg.is_long( &val ) )
00442       { field_iter.set_int( (int) val ); }
00443       else
00444       { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
00445
00446       break;
00447     }
00448
00449     case IFT_UINT: {
00450       long val;
00451       if ( EC_succeed == arg.is_long( &val ) )
00452       { field_iter.set_uint( (unsigned int) val ); }
00453       else
00454       { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
00455
00456       break;
00457     }
00458
00459     case IFT_LONGINT: {
00460       long val;
00461       if ( EC_succeed == arg.is_long( &val ) )
00462       { field_iter.set_longint( val ); }
00463       else
00464       { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
00465
00466       break;
00467     }
00468
00469     case IFT_LONGUINT: {
00470       long val;
00471       if ( EC_succeed == arg.is_long( &val ) )
00472       { field_iter.set_longuint( (long unsigned int) val ); }
00473       else
00474       { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
00475
00476       break;
00477     }
00478
00479     case IFT_FLOAT: {
00480       double val;
00481       if ( EC_succeed == arg.is_double( &val ) )
00482       { field_iter.set_float( (float) val ); }
00483       else
00484       { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
00485
00486       break;
00487     }
00488
00489     case IFT_STRING: {
00490       char* val;
00491       if ( EC_succeed == arg.is_string( &val ) )
00492       { field_iter.set_string( val ); }
00493       else
00494       { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
00495
00496       break;
00497     }
00498
00499     default:
00500       break;
00501     }
00502   }
00503 }