Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
fawkes_bb_interface.cpp
1 
2 /***************************************************************************
3  * fawkes_bb_interface.h - External predicates to access Fawkes interfaces
4  *
5  * Created: Wed Jul 15 16:20:04 2009
6  * Copyright 2009 Daniel Beck
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "fawkes_bb_interface.h"
24 #include <plugins/readylogagent/eclipse_thread.h>
25 
26 #include <core/exceptions/software.h>
27 #include <interface/interface.h>
28 #include <interfaces/ObjectPositionInterface.h>
29 
30 #include <eclipseclass.h>
31 
32 #include <cstdio>
33 #include <cstdlib>
34 #include <cstring>
35 #include <map>
36 #include <string>
37 #include <list>
38 
39 using namespace std;
40 using namespace fawkes;
41 
42 EC_word construct_iface_struct( Interface* iface );
43 EC_word construct_msg_struct( const char* iface_type, Message* msg );
44 EC_word* construct_struct_args( const InterfaceFieldIterator& begin,
45  const InterfaceFieldIterator& end,
46  unsigned int num_fields );
47 void parse_struct_args( EC_word iface_struct,
48  const InterfaceFieldIterator& begin,
49  const InterfaceFieldIterator& end,
50  unsigned int num_fields );
51 
52 int
53 p_read_interface()
54 {
55  // read_interface(+IdStr, -DataStruct)
56  // DataStruct is bound to a struct with named elements. The name of
57  // that struct is data_InterfaceType, the fields are named in the
58  // same way as the fields of the interface.
59 
60  // check if interface with given id is available
61  Interface* interface;
62  char* id;
63 
64  // get interface id
65  if ( EC_succeed != EC_arg( 1 ).is_string( &id ) )
66  {
67  printf( "First argument of read_interface/2 is not a string\n" );
68  return EC_fail;
69  }
70 
71  // get interface
73  if ( !interface )
74  {
75  printf( "Interface with id %s is not available to the agent\n", id );
76  return EC_fail;
77  }
78 
79  // construct data structure
80  EC_word iface_struct;
81  try
82  {
83  iface_struct = construct_iface_struct( interface );
84  }
85  catch ( Exception& e )
86  {
87  e.print_trace();
88  return EC_fail;
89  }
90 
91  // bind 2nd argument
92  return unify( EC_arg(2), iface_struct );
93 }
94 
95 int
96 p_write_interface()
97 {
98  // write_interface(+IdStr, +DataStruct)
99  // The structure passed as the second argument has to be of type
100  // data_InterfaceType such that the interface type matches the type
101  // of the interface with the given id.
102 
103  char* id;
104  Interface* interface;
105 
106  // get interface id
107  if ( EC_succeed != EC_arg( 1 ).is_string( &id ) )
108  {
109  printf( "Firste argument of write_interface/2 is not a string\n" );
110  return EC_fail;
111  }
112 
113  // get interface
115  if ( !interface )
116  {
117  printf( "Interface with id %s is not available to the agent\n", id );
118  return EC_fail;
119  }
120 
121  // get functor of 2nd argument
122  EC_functor fctor;
123  if ( EC_succeed != EC_arg( 2 ).functor( &fctor ) )
124  {
125  printf( "Second argument of writer_interface/2 is not a compound term\n" );
126  return EC_fail;
127  }
128 
129  // check interface type
130  char* iface_type = 0;
131  if ( 1 != sscanf( fctor.name(), "data_%s", iface_type ) ||
132  0 != strcmp( interface->type(), iface_type ) )
133  {
134  printf( "Second argument of write_interface/2 is not of type data_%s but of type %s\n",
135  interface->type(), fctor.name() );
136  free( iface_type );
137  return EC_fail;
138  }
139  free( iface_type );
140 
141  // check arity
142  unsigned int arity = (unsigned int) EC_arg( 2 ).arity();
143  if ( interface->num_fields() != arity )
144  {
145  printf( "Second argument of write_interface/2 has wrong arity\n" );
146  return EC_fail;
147  }
148 
149  // copy data
150  try
151  {
152  parse_struct_args( EC_word( 2 ),
153  interface->fields(),
154  interface->fields_end(),
155  interface->num_fields() );
156  }
157  catch ( Exception& e )
158  {
159  e.print_trace();
160  return EC_fail;
161  }
162 
163  return EC_succeed;
164 }
165 
166 int
167 p_send_message()
168 {
169  // send_message(id, data_InterfaceType_MessageType{key1:param1, ...})
170 
171  // check if interface with given id is available
172  char* iface_id;
173  Interface* interface;
174 
175  // get interface id
176  if ( EC_succeed != EC_arg( 1 ).is_string( &iface_id ) )
177  {
178  printf( "First argument of send_message/2 is not an atom\n" );
179  return EC_fail;
180  }
181 
182  // get interface
183  interface = EclipseAgentThread::instance()->get_registered_interface( iface_id );
184  if ( !interface )
185  {
186  printf( "Interface with id %s is not available to the agent\n", iface_id );
187  return EC_fail;
188  }
189 
190  // check functor of 2nd argument
191  EC_functor fctor;
192  if ( EC_succeed != EC_arg( 2 ).functor( &fctor ) )
193  {
194  printf( "Second argument of send_message/2 has no functor\n" );
195  return EC_fail;
196  }
197 
198  char* fctor_name = strdup( fctor.name() );
199  strtok( fctor_name, "_" );
200  char* iface_type = strtok( NULL, "_" );
201  char* msg_type = strtok( NULL, "_" );
202 
203  if ( !iface_type ||
204  !msg_type ||
205  0 != strcmp( interface->type(), iface_type ) )
206  {
207  printf( "Malformed functor: %s\n", fctor.name() );
208  return EC_fail;
209  }
210 
211  // create message of given type
212  Message* msg;
213  try
214  {
215  msg = interface->create_message( msg_type );
216  }
217  catch ( UnknownTypeException& e )
218  {
219  printf( "Message type %s is not available for interfaces of type %s\n",
220  msg_type, interface->type() );
221  return EC_fail;
222  }
223 
224  // cleanup
225  free( fctor_name );
226 
227  // parse parameters
228  try
229  {
230  parse_struct_args( EC_arg( 2 ), msg->fields(), msg->fields_end(), msg->num_fields() );
231  }
232  catch ( Exception& e )
233  {
234  e.print_trace();
235  return EC_fail;
236  }
237 
238  // enqueue message
239  interface->msgq_enqueue( msg );
240 
241  return EC_succeed;
242 }
243 
244 int
245 p_recv_messages()
246 {
247  // recv_messages( +IdStr, -MsgList )
248  // MsgList is a list of message type structurs. The last message in
249  // the list is the most recent one.
250 
251  // check if interface with given id is available
252  char* iface_id;
253  Interface* interface;
254 
255  if ( EC_succeed != EC_arg( 1 ).is_string( &iface_id ) )
256  {
257  printf( "First argument of send_message/2 is not an atom\n" );
258  return EC_fail;
259  }
260 
261  interface = EclipseAgentThread::instance()->get_registered_interface( iface_id );
262  if ( !interface )
263  {
264  printf( "Interface with id %s is not available to the agent\n", iface_id );
265  return EC_fail;
266  }
267 
268  std::list< EC_word > messages;
269 
270  while ( !interface-> msgq_empty() )
271  {
272  Message* msg = interface->msgq_first();
273  EC_word msg_struct;
274 
275  try
276  {
277  msg_struct = construct_msg_struct( interface->type(), msg );
278  }
279  catch( Exception& e )
280  {
281  e.print_trace();
282  return EC_fail;
283  }
284 
285  messages.push_back( msg_struct );
286 
287  interface->msgq_pop();
288  }
289 
290  EC_word l = nil();
291  while( !messages.empty() )
292  {
293  l = ::list( messages.front(), l );
294  messages.pop_front();
295  }
296 
297  return unify( EC_arg( 2 ), l );
298 }
299 
300 EC_word
301 construct_iface_struct( Interface* iface )
302 {
303  EC_word* args = construct_struct_args( iface->fields(),
304  iface->fields_end(),
305  iface->num_fields() );
306 
307  char* fctor;
308  asprintf( &fctor, "data_%s", iface->type() );
309 
310  EC_word ret = term( EC_functor( fctor, iface->num_fields() ), args );
311 
312  delete[] args;
313  free( fctor );
314 
315  return ret;
316 }
317 
318 EC_word
319 construct_msg_struct( const char* iface_type, Message* msg )
320 {
321  EC_word* args = construct_struct_args( msg->fields(), msg->fields_end(), msg->num_fields() );
322 
323  char* fctor;
324  asprintf( &fctor, "data_%s_%s", iface_type, msg->type() );
325 
326  EC_word ret = term( EC_functor( fctor, msg->num_fields() ), args );
327 
328  delete[] args;
329  free( fctor );
330 
331  return ret;
332 }
333 
334 EC_word*
335 construct_struct_args( const InterfaceFieldIterator& begin,
336  const InterfaceFieldIterator& end,
337  unsigned int num_fields )
338 {
339  EC_word* args = new EC_word[ num_fields ];
340 
341  InterfaceFieldIterator field_iter;
342  unsigned int field_idx;
343  for ( field_iter = begin, field_idx = 0;
344  field_iter != end;
345  ++field_iter, ++field_idx )
346  {
347  interface_fieldtype_t type = field_iter.get_type();
348 
349  switch ( type )
350  {
351  case IFT_BOOL: {
352  char* t = strdup( "true" );
353  char* f = strdup( "fail" );
354 
355  args[ field_idx ] = field_iter.get_bool() ? EC_atom( t ) : EC_atom( f );
356 
357  free( t );
358  free( f );
359 
360  break;
361  }
362 
363  case IFT_INT32:
364  args[ field_idx ] = EC_word( field_iter.get_int32() );
365  break;
366 
367  case IFT_UINT32:
368  args[ field_idx ] = EC_word( (long) field_iter.get_uint32() );
369  break;
370 
371  case IFT_INT64:
372  args[ field_idx ] = EC_word( field_iter.get_int64() );
373  break;
374 
375  case IFT_UINT64:
376  args[ field_idx ] = EC_word( (long) field_iter.get_uint64() );
377  break;
378 
379  case IFT_FLOAT:
380  args[ field_idx ] = EC_word( field_iter.get_float() );
381  break;
382 
383  case IFT_STRING:
384  args[ field_idx ] = EC_word( field_iter.get_string() );
385  break;
386 
387  case IFT_BYTE:
388  args[ field_idx ] = EC_word( field_iter.get_byte() );
389  break;
390 
391  default:
392  throw UnknownTypeException( "Field of unknown type %s", field_iter.get_typename() );
393  }
394  }
395 
396  return args;
397 }
398 
399 void
400 parse_struct_args( EC_word data_struct,
401  const InterfaceFieldIterator& begin,
402  const InterfaceFieldIterator& end,
403  unsigned int num_fields )
404 {
405  unsigned int field_idx;
406  InterfaceFieldIterator field_iter;
407 
408  for ( field_iter = begin, field_idx = 1;
409  field_iter != end;
410  ++field_iter, ++field_idx )
411  {
412  interface_fieldtype_t type = field_iter.get_type();
413 
414  EC_word arg;
415  if ( EC_succeed != data_struct.arg( field_idx, arg ) )
416  { throw Exception( "Failed to parse interface data. Couldn't read %d-th parameter.\n", field_idx ); }
417 
418  switch( type )
419  {
420  case IFT_BOOL: {
421  char* t = strdup( "true" );
422  char* f = strdup( "fail" );
423  if ( EC_succeed == arg.unify( EC_atom( t ) ) )
424  { field_iter.set_bool( true ); }
425  else if ( EC_succeed == arg.unify( EC_atom( f ) ) )
426  { field_iter.set_bool( false ); }
427  else
428  {
429  free( t );
430  free( f );
431  throw TypeMismatchException( "Wrong data type for %d-th argument\n", field_idx );
432  }
433 
434  free( t );
435  free( f );
436 
437  break;
438  }
439 
440  case IFT_INT32: {
441  long val;
442  if ( EC_succeed == arg.is_long( &val ) )
443  { field_iter.set_int32( (int) val ); }
444  else
445  { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
446 
447  break;
448  }
449 
450  case IFT_UINT32: {
451  long val;
452  if ( EC_succeed == arg.is_long( &val ) )
453  { field_iter.set_uint32( (unsigned int) val ); }
454  else
455  { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
456 
457  break;
458  }
459 
460  case IFT_INT64: {
461  long val;
462  if ( EC_succeed == arg.is_long( &val ) )
463  { field_iter.set_int64( val ); }
464  else
465  { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
466 
467  break;
468  }
469 
470  case IFT_UINT64: {
471  long val;
472  if ( EC_succeed == arg.is_long( &val ) )
473  { field_iter.set_uint64( (long unsigned int) val ); }
474  else
475  { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
476 
477  break;
478  }
479 
480  case IFT_FLOAT: {
481  double val;
482  if ( EC_succeed == arg.is_double( &val ) )
483  { field_iter.set_float( (float) val ); }
484  else
485  { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
486 
487  break;
488  }
489 
490  case IFT_STRING: {
491  char* val;
492  if ( EC_succeed == arg.is_string( &val ) )
493  { field_iter.set_string( val ); }
494  else
495  { throw TypeMismatchException( "Wrong data type for %d-the argument\n", field_idx ); }
496 
497  break;
498  }
499 
500  default:
501  break;
502  }
503  }
504 }