Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
interface.cpp
1 
2 /***************************************************************************
3  * interface.cpp - BlackBoard Interface
4  *
5  * Created: Mon Oct 09 18:54:50 2006
6  * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
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. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <interface/interface.h>
25 
26 #include <interface/mediators/interface_mediator.h>
27 #include <interface/mediators/message_mediator.h>
28 #include <core/threading/refc_rwlock.h>
29 #include <core/threading/mutex.h>
30 #include <core/exceptions/system.h>
31 #include <utils/time/clock.h>
32 #include <utils/time/time.h>
33 #include <utils/misc/strndup.h>
34 
35 #include <cstring>
36 #include <cstdio>
37 #include <cstdlib>
38 #include <cerrno>
39 #include <typeinfo>
40 #include <regex.h>
41 
42 namespace fawkes {
43 
44 /** @class InterfaceWriteDeniedException <interface/interface.h>
45  * This exception is thrown if a write has been attempted on a read-only interface.
46  * @see Interface::write()
47  * @ingroup Exceptions
48  */
49 
50 /** Constructor.
51  * @param type type of the interface which caused the exception
52  * @param id id of the interface which caused the exception
53  * @param msg additional informative message
54  */
56  const char *id,
57  const char *msg)
58  : Exception("This interface instance '%s' of type '%s' is not opened for writing. %s",
59  id, type, msg)
60 {
61 }
62 
63 /** @class InterfaceMessageEnqueueException <interface/interface.h>
64  * This exception is thrown if a write has been attempted on a read-only interface.
65  * @see Interface::write()
66  * @ingroup Exceptions
67  */
68 
69 /** Constructor.
70  * @param type type of the interface which caused the exception
71  * @param id id of the interface which caused the exception
72  */
74  const char *id)
75  : Exception("This interface instance '%s' of type '%s' IS opened for writing, but "
76  "messages can only be enqueued on reading interfaces.", id, type)
77 {
78 }
79 
80 /** @class InterfaceInvalidMessageException <interface/interface.h>
81  * This exception is thrown if a message has been queued in the interface which is
82  * not recognized by the interface.
83  * @ingroup Exceptions
84  */
85 
86 /** Constructor.
87  * @param interface interface that the invalid message was enqueued to
88  * @param message enqueued message
89  */
91  const Message *message)
92  : Exception("Message of type '%s' cannot be enqueued in interface of type '%s'",
93  message->type(), interface->type())
94 {
95 }
96 
97 
98 /** @class InterfaceInvalidException <interface/interface.h>
99  * This exception is thrown if an interface is invalid and it is attempted to call
100  * read()/write().
101  * @ingroup Exceptions
102  */
103 
104 /** Constructor.
105  * @param interface invalid interface that the operation was tried on
106  * @param method the method that was tried to execute
107  */
109  const char *method)
110  : Exception("The interface %s (instance serial %u) is invalid. You cannot call %s anymore.",
111  interface->uid(), interface->serial(), method)
112 {
113 }
114 
115 
116 /** @class Interface <interface/interface.h>
117  * Base class for all Fawkes BlackBoard interfaces.
118  *
119  * Interfaces are identified by a type and an ID. The type is just a
120  * textual representation of the class name. The ID identifies a
121  * specific instance of this interface type. Additionally each
122  * interface has a hash. The hash is an MD5 digest of the XML config
123  * file that was fed to the interface generator to create the
124  * interface. It is used to detect incompatible versions of the same
125  * interface type.
126  *
127  * Interfaces have at least two sections of memory which contains a
128  * struct composed of the internal data of the interface. The first is
129  * shared with either the LocalBlackBoard instance (and hence all
130  * other instances of the interface) or with a transmission thread of
131  * a RemoteBlackBoard. The second is a private copy of the data. The
132  * data is copied between the shared and private section only upon
133  * request. Interfaces are either reading or writing, denoting their
134  * kind of access towards the shared memory section. At any point in
135  * time there may at most exist one writer for an interface, but any
136  * number of readers. The shared section is protected by a
137  * ReadWriteLock. For a writer, a call to write() will copy the data
138  * from the private to the shared section. For a reader, a call to
139  * read() will copy the data from the shared to the private
140  * section. Upon opening the interface, the private section is copied
141  * once from the shared section, even when opening a writer.
142  *
143  * An interface has an internal timestamp. This timestamp indicates
144  * when the data in the interface has been modified last. The
145  * timestamp is usually automatically updated. But it some occasions
146  * the writer may choose to provide its own timestamp data. This can
147  * be useful for example for an interface providing hardware data to
148  * give the exact capture time. In the automatic case nothing has to
149  * be done manually. The timestamp is updated automatically by calling
150  * the write() method if and only if the data in the interface has
151  * actually been modified. The reader can call changed() to see if the
152  * data changed. In the non-automatic case the writer must first
153  * disable automatic timestamping using set_auto_timestamping(). Then
154  * it must provide a timestamp everytime before calling write(). Note
155  * that setting the timestamp already marks the interface as having
156  * changed. So set the timestamp only if the data has changed and the
157  * readers should see this.
158  *
159  * An interface provides support for buffers. Like the shared and
160  * private memory sections described above, buffers are additional
161  * memory sections that can be used to save data from the shared
162  * section or save or restore from and to the private memory
163  * section. One example use case is to save the current shared memory
164  * content at one point in time at a specific main loop hook, and
165  * restore it only later at a suitable time in another continuous
166  * thread. Another useful application is to keep a history for
167  * hysteresis processing, or to observe the development of the values
168  * in an interface.
169  *
170  * Interfaces are not created directly, but rather by using the
171  * interface generator.
172  *
173  * @author Tim Niemueller
174  */
175 
176 /** @var Interface::data_ptr
177  * Pointer to local memory storage
178  */
179 
180 /** @var Interface::data_ts
181  * Pointer to data casted to timestamp struct. This assumes that the very
182  * first two entries are 64 bit wide signed integers containing seconds and
183  * microseconds since the Unix epoch.
184  */
185 
186 /** @var Interface::data_size
187  * Minimal data size to hold data storage.
188  */
189 
190 /** @var Interface::data_changed
191  * Indicator if data has changed.
192  * This must be set by all methods that manipulate internal data or the
193  * timestamp. Only if set to true a call to write() will update data_ts.
194  */
195 
196 /** @fn bool Interface::message_valid(const Message *message) const = 0
197  * Check if the message is valid and can be enqueued.
198  * @param message The message to check
199  * @return true, if the message is valid and may be enqueued, false otherwise
200  *
201  * @fn bool Interface::create_message(const char *type) const = 0
202  * Create message based on type name.
203  * This will create a new message of the given type. The type must be
204  * given without the InterfaceName:: prefix but just the plain class
205  * name of the message.
206  * @param type message type
207  * @return message of the given type, empty
208  * @exception UnknownTypeException thrown if this interface cannot
209  * create a message of the given type.
210  *
211  * @fn void Interface::copy_values(const Interface *interface) = 0
212  * Copy values from another interface.
213  * The operation will only succeed if the supplied interface is of the same
214  * type as this instance.
215  * @param interface interface to copy from
216  *
217  * @fn const char * Interface::enum_tostring(const char *enumtype, int val) const
218  * Convert arbitrary enum value to string.
219  * Given the string representation of the enum type and the value this method
220  * returns the string representation of the specific value, or the string
221  * UNKNOWN if the value is not defined. An exception is thrown if the enum
222  * type is invalid.
223  * @param enumtype enum type as string
224  * @param val value to convert
225  * @return string representation of value
226  * @exception UnknownTypeException thrown if enumtype is not specified for
227  * interface.
228  */
229 
230 /** Constructor */
232 {
233  __write_access = false;
234  __rwlock = NULL;
235  __valid = true;
236  __next_message_id = 0;
237  __num_fields = 0;
238  __fieldinfo_list = NULL;
239  __messageinfo_list = NULL;
240  __clock = Clock::instance();
241  __timestamp = new Time(0, 0);
242  __local_read_timestamp = new Time(0, 0);
243  __auto_timestamping = true;
244  data_changed = false;
245  memset(__hash, 0, __INTERFACE_HASH_SIZE);
246  memset(__hash_printable, 0, __INTERFACE_HASH_SIZE * 2 + 1);
247 
248  data_ptr = NULL;
249  data_size = 0;
250 
251  __buffers = NULL;
252  __num_buffers = 0;
253 
254  __message_queue = new MessageQueue();
255  __data_mutex = new Mutex();
256 }
257 
258 
259 /** Destructor */
261 {
262  if ( __rwlock) __rwlock->unref();
263  delete __data_mutex;
264  delete __message_queue;
265  if (__buffers) free(__buffers);
266  // free fieldinfo list
267  interface_fieldinfo_t *finfol = __fieldinfo_list;
268  while ( finfol ) {
269  __fieldinfo_list = __fieldinfo_list->next;
270  free(finfol);
271  finfol = __fieldinfo_list;
272  }
273  // free messageinfo list
274  interface_messageinfo_t *minfol = __messageinfo_list;
275  while ( minfol ) {
276  __messageinfo_list = __messageinfo_list->next;
277  free(minfol);
278  minfol = __messageinfo_list;
279  }
280  delete __timestamp;
281  delete __local_read_timestamp;
282 }
283 
284 /** Get interface hash.
285  * The interface is a unique version identifier of an interface. It is
286  * the has of the input XML file during the generation of the
287  * interface. It is meant to be used to ensure that all sides are
288  * using the exact same version of an interface.
289  * @return constant byte string containing the hash value of hash_size() length
290  */
291 const unsigned char *
293 {
294  return __hash;
295 }
296 
297 
298 /** Get printable interface hash.
299  * @return printable version of hash()
300  */
301 const char *
303 {
304  return __hash_printable;
305 }
306 
307 
308 /** Set hash. Never use directly.
309  * @param ihash interface hash
310  */
311 void
312 Interface::set_hash(unsigned char *ihash)
313 {
314  memcpy(__hash, ihash, __INTERFACE_HASH_SIZE);
315  for (size_t s = 0; s < __INTERFACE_HASH_SIZE; ++s) {
316  snprintf(&__hash_printable[s*2], 3, "%02X", __hash[s]);
317  }
318 }
319 
320 
321 /** Add an entry to the field info list.
322  * Never use directly, use the interface generator instead. The info list
323  * is used for introspection purposes to allow for iterating over all fields
324  * of an interface.
325  * @param type field type
326  * @param name name of the field, this is referenced, not copied
327  * @param length length of the field
328  * @param value pointer to the value in the data struct
329  * @param enumtype name of the enum type, valid only if type == IFT_ENUM.
330  */
331 void
333  size_t length, void *value, const char *enumtype)
334 {
335  interface_fieldinfo_t *infol = __fieldinfo_list;
336  interface_fieldinfo_t *newinfo =
337  (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
338 
339  newinfo->type = type;
340  newinfo->enumtype = enumtype;
341  newinfo->name = name;
342  newinfo->length = length;
343  newinfo->value = value;
344  newinfo->next = NULL;
345 
346  if ( infol == NULL ) {
347  // first entry
348  __fieldinfo_list = newinfo;
349  } else {
350  // append to list
351  while ( infol->next != NULL ) {
352  infol = infol->next;
353  }
354  infol->next = newinfo;
355  }
356 
357  ++__num_fields;
358 }
359 
360 
361 /** Add an entry to the message info list.
362  * Never use directly, use the interface generator instead. The info list
363  * is used for introspection purposes to allow for iterating over all message
364  * types of an interface.
365  * @param type the type of the message
366  */
367 void
368 Interface::add_messageinfo(const char *type)
369 {
370  interface_messageinfo_t *infol = __messageinfo_list;
371  interface_messageinfo_t *newinfo =
373 
374  newinfo->type = type;
375  newinfo->next = NULL;
376 
377  if ( infol == NULL ) {
378  // first entry
379  __messageinfo_list = newinfo;
380  } else {
381  // append to list
382  while ( infol->next != NULL ) {
383  infol = infol->next;
384  }
385  infol->next = newinfo;
386  }
387 }
388 
389 
390 /** Obtain a list of textual representations of the message types
391  * available for this interface.
392  * @return the message types
393  */
394 std::list<const char *>
396 {
397  std::list<const char *> types;
398  interface_messageinfo_t *cur = __messageinfo_list;
399 
400  while ( cur != NULL ) {
401  types.push_back(cur->type);
402  cur = cur->next;
403  }
404 
405  return types;
406 }
407 
408 
409 /** Get size of interface hash.
410  * Returns the size in bytes of the interface hash. This depends on the used hash.
411  * @return size of interface hash string
412  */
413 size_t
415 {
416  return __INTERFACE_HASH_SIZE;
417 }
418 
419 
420 /** Get data chunk.
421  * Use sparsely
422  * @return const pointer to the data chunk
423  */
424 const void *
426 {
427  return data_ptr;
428 }
429 
430 
431 /** Check if this is a writing instance.
432  * @return true if this is a writing instance, false otherwise
433  */
434 bool
436 {
437  return __write_access;
438 }
439 
440 
441 /** Mark this interface invalid.
442  * An interface can become invalid, for example if the connection of a
443  * RemoteBlackBoard dies. In this case the interface becomes invalid
444  * and successive read()/write() calls will throw an
445  * InterfaceInvalidException.
446  * @param valid true to mark the interface valid or false to mark it invalid
447  */
448 void
450 {
451  __rwlock->lock_for_write();
452  __valid = valid;
453  __rwlock->unlock();
454 }
455 
456 
457 /** Check validity of interface.
458  * @return true if interface is valid, false otherwise
459  */
460 bool
462 {
463  return __valid;
464 }
465 
466 
467 /** Read from BlackBoard into local copy.
468  * @exception InterfaceInvalidException thrown if the interface has
469  * been marked invalid
470  */
471 void
473 {
474  __rwlock->lock_for_read();
475  __data_mutex->lock();
476  if ( __valid ) {
477  memcpy(data_ptr, __mem_data_ptr, data_size);
478  *__local_read_timestamp = *__timestamp;
480  } else {
481  __data_mutex->unlock();
482  __rwlock->unlock();
483  throw InterfaceInvalidException(this, "read()");
484  }
485  __data_mutex->unlock();
486  __rwlock->unlock();
487 }
488 
489 
490 /** Write from local copy into BlackBoard memory.
491  * @exception InterfaceInvalidException thrown if the interface has
492  * been marked invalid
493  */
494 void
496 {
497  if ( ! __write_access ) {
498  throw InterfaceWriteDeniedException(__type, __id, "Cannot write.");
499  }
500 
501  __rwlock->lock_for_write();
502  __data_mutex->lock();
503  if ( __valid ) {
504  if (data_changed) {
505  if (__auto_timestamping) __timestamp->stamp();
506  long sec = 0, usec = 0;
507  __timestamp->get_timestamp(sec, usec);
508  data_ts->timestamp_sec = sec;
509  data_ts->timestamp_usec = usec;
510  data_changed = false;
511  }
512  memcpy(__mem_data_ptr, data_ptr, data_size);
513  } else {
514  __data_mutex->unlock();
515  __rwlock->unlock();
516  throw InterfaceInvalidException(this, "write()");
517  }
518  __data_mutex->unlock();
519  __rwlock->unlock();
520 
521  __interface_mediator->notify_of_data_change(this);
522 }
523 
524 
525 /** Get data size.
526  * @return size in bytes of data segment
527  */
528 unsigned int
530 {
531  return data_size;
532 }
533 
534 
535 /** Set type, ID and UID.
536  * Sets type and ID, UID is generated automatically as Type::ID.
537  * @param type string, a maxmimum of __INTERFACE_TYPE_SIZE bytes are copied
538  * @param ID string, a maxmimum of __INTERFACE_ID_SIZE bytes are copied
539  */
540 void
541 Interface::set_type_id(const char *type, const char *id)
542 {
543  __type[__INTERFACE_TYPE_SIZE] = 0;
544  __id[__INTERFACE_ID_SIZE] = 0;
545  __uid[__INTERFACE_UID_SIZE] = 0;
546  strncpy(__type, type, __INTERFACE_TYPE_SIZE);
547  strncpy(__id, id, __INTERFACE_ID_SIZE);
548  snprintf(__uid, __INTERFACE_UID_SIZE, "%s::%s", type, id);
549 }
550 
551 
552 /** Set instance serial.
553  * @param instance_serial instance serial
554  */
555 void
556 Interface::set_instance_serial(unsigned short instance_serial)
557 {
558  __instance_serial = instance_serial;
559 }
560 
561 
562 /** Set mediators.
563  * @param iface_mediator interface mediator
564  * @param msg_mediator message mediator.
565  */
566 void
567 Interface::set_mediators(InterfaceMediator *iface_mediator,
568  MessageMediator *msg_mediator)
569 {
570  __interface_mediator = iface_mediator;
571  __message_mediator = msg_mediator;
572 }
573 
574 
575 /** Set memory data.
576  * @param serial mem serial
577  * @param real_ptr pointer to whole chunk
578  * @param data_ptr pointer to data chunk
579  */
580 void
581 Interface::set_memory(unsigned int serial, void *real_ptr, void *data_ptr)
582 {
583  __mem_serial = serial;
584  __mem_real_ptr = real_ptr;
585  __mem_data_ptr = data_ptr;
586 }
587 
588 
589 /** Set read/write info.
590  * @param write_access true to enable write access, false for read-only
591  * @param rwlock read/write lock for this interface
592  */
593 void
594 Interface::set_readwrite(bool write_access, RefCountRWLock *rwlock)
595 {
596  __write_access = write_access;
597  __rwlock = rwlock;
598 }
599 
600 
601 /** Check equality of two interfaces.
602  * Two interfaces are the same if their types and identifiers are
603  * equal. This does not mean that both interfaces are the very same
604  * instance for accessing the BlackBoard. Instead this just means that
605  * both instances will access the same chunk of memory in the
606  * BlackBoard and the instances MAY be the same. If you want to know
607  * if two instances are exactly the same compare the instance serials
608  * using the serial() method.
609  * @param comp interface to compare current instance with
610  * @return true, if interfaces point to the same data, false otherwise
611  */
612 bool
614 {
615  return ( (strncmp(__type, comp.__type, sizeof(__type)) == 0) &&
616  (strncmp(__id, comp.__id, sizeof(__id)) == 0) );
617 }
618 
619 
620 /** Check if interface is of given type.
621  * @param interface_type type to query
622  * @return true, if current instance is of given type, false otherwise
623  */
624 bool
625 Interface::oftype(const char *interface_type) const
626 {
627  return (strncmp(this->__type, interface_type, sizeof(this->__type)) == 0);
628 }
629 
630 
631 /** Get type of interface.
632  * @return string with the type of the interface.
633  */
634 const char *
636 {
637  return __type;
638 }
639 
640 
641 /** Get identifier of interface.
642  * @return string with the identifier of the interface.
643  */
644 const char *
646 {
647  return __id;
648 }
649 
650 
651 /** Get unique identifier of interface.
652  * As the name suggests this ID denotes a unique memory instance of
653  * this interface in the blackboard. It is provided by the system and
654  * currently returns a string of the form "type::id", where type is
655  * replaced by the type returned by type() and id is the ID returned
656  * by id().
657  * @return string with the unique identifier of the interface.
658  */
659 const char *
661 {
662  return __uid;
663 }
664 
665 
666 /** Get instance serial of interface.
667  * @return instance serial of the interface.
668  */
669 unsigned short
671 {
672  return __instance_serial;
673 }
674 
675 
676 /** Get memory serial of interface.
677  * @return memory serial of interface
678  */
679 unsigned int
681 {
682  return __mem_serial;
683 }
684 
685 
686 /** Get timestamp of last write.
687  * Note that you need to call read() before this provides useful information.
688  * @return timestamp of last write.
689  */
690 const Time *
692 {
693  return __timestamp;
694 }
695 
696 
697 /** Set timestamp.
698  * @param t time stamp to copy time from, if NULL current time is queried
699  * from clock.
700  */
701 void
703 {
704  if (__auto_timestamping) throw Exception("Auto timestamping enabled, cannot "
705  "set explicit timestamp");
706  if (!__write_access) throw Exception("Timestamp can only be set on writing "
707  "instance");
708 
709  if (t) {
710  *__timestamp = t;
711  } else {
712  __timestamp->stamp();
713  }
714  data_changed = true;
715 }
716 
717 
718 /** Set clock to use for timestamping.
719  * @param clock clock to use from now on
720  */
721 void
723 {
724  __clock = clock;
725  __timestamp->set_clock(clock);
726 }
727 
728 
729 /** Enable or disable automated timestamping.
730  * @param enabled true to enable automated timestamping, false to disable
731  */
732 void
734 {
735  __auto_timestamping = enabled;
736 }
737 
738 
739 /** Check if data has been changed.
740  * Note that if the data has been modified this method will return
741  * true at least until the next call to read. From then on it will
742  * return false if the data has not been modified between the two
743  * read() calls and still true otherwise.
744  * @return true if data has been changed between the last call to
745  * read() and the one before.
746  */
747 bool
749 {
750  return (*__timestamp != __local_read_timestamp);
751 }
752 
753 
754 /** Set from a raw data chunk.
755  * This allows for setting the interface data from a raw chunk. This
756  * is not useful in general but only in rare situations like network
757  * transmission. Do not use it unless you really know what you are
758  * doing. The method expects the chunk to be exactly of the size
759  * returned by datasize(). No check is done, a segfault will most
760  * likely occur if you provide invalid data.
761  * @param chunk data chunk, must be exactly of the size that is
762  * returned by datasize()
763  */
764 void
766 {
767  // This could be checked but should never happen with our generated
768  // interfaces anyway
769  // if ( data_ptr == NULL )
770  // throw NullPointerException("Interface not initialized");
771 
772  memcpy(data_ptr, chunk, data_size);
773 }
774 
775 /** Check if there is a writer for the interface.
776  * Use this method to determine if there is any open instance of the
777  * interface that is writing to the interface. This can also be the
778  * queried interface instance.
779  * @return true if a writer for the interface exists, false otherwise
780  */
781 bool
783 {
784  return __interface_mediator->exists_writer(this);
785 }
786 
787 
788 /** Get the number of readers.
789  * Use this method to determine how many reading instances of the
790  * interface currently exist. If the current instance is a reading
791  * instance it will be included in the count number. To determine if
792  * you are the last man having this interface you can use the
793  * following code:
794  * @code
795  * // for a writing instance:
796  * if ( interface->num_readers == 0 ) {
797  * // we are the last one to have this interface open
798  * }
799  *
800  * // for a reading instance:
801  * if ( ! interface->has_writer() && (interface->num_readers() == 0) ) {
802  * // we are the last one to have this interface open
803  * }
804  * @endcode
805  * Note that this can result in a race condition. You have to be
806  * registered as a BlackBoardEventListener to be sure that you are
807  * really the last.
808  * @return number of readers
809  */
810 unsigned int
812 {
813  return __interface_mediator->num_readers(this);
814 }
815 
816 
817 /** Enqueue message at end of queue.
818  * This appends the given message to the queue and transmits the
819  * message via the message mediator. The message is afterwards owned
820  * by the other side and will be unrefed and freed as soon as it has
821  * been processed. If you want to keep this message to read a feedback
822  * status you have to reference it _before_ enqueuing it!
823  * This can only be called on a reading interface instance.
824  * @param message Message to enqueue.
825  * @return message id after message has been queued
826  * @exception MessageAlreadyQueuedException thrown if the message has
827  * already been enqueued to an interface.
828  */
829 unsigned int
831 {
832  if ( __write_access ) {
833  throw InterfaceMessageEnqueueException(__type, __id);
834  }
835 
836  if ( message_valid(message) ) {
837  message->set_interface(this);
838  message->set_id(next_msg_id());
839  // transmit might change the message id!
840  __message_mediator->transmit(message);
841  unsigned int msgid = message->id();
842  message->unref();
843  return msgid;
844  } else {
845  throw InterfaceInvalidMessageException(this, message);
846  }
847 }
848 
849 
850 /** Enqueue copy of message at end of queue.
851 
852  * This method creates a copy of the message and enqueues it. Note
853  * that this way you cannot receive status message in the message,
854  * because the other side will not use your message instance but a
855  * copy instead.
856  *
857  * This is particularly useful if you call from an environment with
858  * automatic garbage collection that does not honor the referencing
859  * feature of message but rather just deletes it.
860  *
861  * This can only be called on a reading interface instance.
862  *
863  * @param message Message to enqueue.
864  * @return message id after message has been queued
865  * @exception MessageAlreadyQueuedException thrown if the message has already been
866  * enqueued to an interface.
867  */
868 unsigned int
870 {
871  if ( __write_access ) {
872  throw InterfaceMessageEnqueueException(__type, __id);
873  }
874  if ( message == NULL ) {
875  throw NullPointerException("Message may not be NULL");
876  }
877 
878  if ( message_valid(message) ) {
879  Message *mcopy = message->clone();
880  mcopy->set_interface(this);
881  mcopy->set_id(next_msg_id());
882  __message_mediator->transmit(mcopy);
883  unsigned int msgid = mcopy->id();
884  mcopy->unref();
885  message->set_id(msgid);
886  return msgid;
887  } else {
888  throw InterfaceInvalidMessageException(this, message);
889  }
890 }
891 
892 
893 /** Enqueue message.
894  * This will enqueue the message without transmitting it via the
895  * message mediator.
896  *
897  * This can only be called on a writing interface instance.
898  * @param message message to enqueue
899  */
900 void
901 Interface::msgq_append(Message *message)
902 {
903  if ( ! __write_access ) {
904  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
905  "reading instance of an interface (append).");
906  }
907 
908  __message_queue->append(message);
909 }
910 
911 
912 /** Remove message from queue.
913  * Removes the given message from the queue. Note that if you
914  * unref()ed the message after insertion this will most likely delete
915  * the object. It is not safe to use the message after removing it
916  * from the queue in general.
917  *
918  * This can only be called on a writing interface instance.
919  *
920  * @param message Message to remove.
921  */
922 void
924 {
925  if ( ! __write_access ) {
926  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
927  "reading instance of an interface (remove msg).");
928  }
929 
930  return __message_queue->remove(message);
931 }
932 
933 
934 /** Remove message from queue.
935  * Removes message with the given ID from the queue.
936  * @param message_id Message ID to remove.
937  * This can only be called on a writing interface instance.
938  */
939 void
940 Interface::msgq_remove(unsigned int message_id)
941 {
942  if ( ! __write_access ) {
943  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
944  "reading instance of an interface (remove id).");
945  }
946 
947  return __message_queue->remove(message_id);
948 }
949 
950 
951 /** Get size of message queue.
952  * This can only be called on a writing interface instance.
953  * @return number of messages in queue.
954  */
955 unsigned int
957 {
958  if ( ! __write_access ) {
959  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
960  "reading instance of an interface (size).");
961  }
962 
963  return __message_queue->size();
964 }
965 
966 
967 /** Check if queue is empty.
968  * This can only be called on a writing interface instance.
969  * @return true if queue is empty, false otherwise
970  */
971 bool
973 {
974  if ( ! __write_access ) {
975  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
976  "reading instance of an interface (empty).");
977  }
978 
979  return __message_queue->empty();
980 }
981 
982 
983 /** Flush all messages.
984  * Deletes all messages from the queue.
985  * This can only be called on a writing interface instance.
986  */
987 void
989 {
990  if ( ! __write_access ) {
991  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
992  "reading instance of an interface (flush).");
993  }
994 
995  __message_queue->flush();
996 }
997 
998 
999 /** Lock message queue.
1000  * Lock the message queue. You have to do this * before using the
1001  * iterator safely.
1002  *
1003  * This can only be called on a writing interface instance.
1004  */
1005 void
1007 {
1008  if ( ! __write_access ) {
1009  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
1010  "reading instance of an interface (lock).");
1011  }
1012 
1013  __message_queue->lock();
1014 }
1015 
1016 
1017 /** Try to lock message queue.
1018  * Try to lock the message queue. Returns immediately and does not
1019  * wait for lock.
1020  *
1021  * This can only be called on a writing interface instance.
1022  * @return true, if the lock has been aquired, false otherwise.
1023  * @see lock()
1024  */
1025 bool
1027 {
1028  if ( ! __write_access ) {
1029  throw InterfaceWriteDeniedException(__type, __id,
1030  "Cannot work on message queue on "
1031  "reading instance of an interface "
1032  "(msgq_try_lock).");
1033  }
1034 
1035  return __message_queue->try_lock();
1036 }
1037 
1038 
1039 /** Unlock message queue.
1040  * Give free the lock on the message queue.
1041  * This can only be called on a writing interface instance.
1042  */
1043 void
1045 {
1046  if ( ! __write_access ) {
1047  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
1048  "reading instance of an interface (unlock).");
1049  }
1050 
1051  __message_queue->unlock();
1052 }
1053 
1054 /** Get start iterator for message queue.
1055  * Not that you must have locked the queue before this operation!
1056  *
1057  * This can only be called on a writing interface instance.
1058  *
1059  * @return iterator to begin of message queue.
1060  * @exception NotLockedException thrown if message queue is not locked
1061  * during this operation.
1062  */
1065 {
1066  if ( ! __write_access ) {
1067  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
1068  "reading instance of an interface (begin).");
1069  }
1070 
1071  return __message_queue->begin();
1072 }
1073 
1074 
1075 /** Get end iterator for message queue.
1076  * Not that you must have locked the queue before this operation!
1077  *
1078  * This can only be called on a writing interface instance.
1079  *
1080  * @return iterator beyond end of message queue.
1081  * @exception NotLockedException thrown if message queue is not locked
1082  * during this operation.
1083  */
1086 {
1087  if ( ! __write_access ) {
1088  throw InterfaceWriteDeniedException(__type, __id,
1089  "Cannot work on message queue on "
1090  "reading instance of an interface (end).");
1091  }
1092 
1093  return __message_queue->end();
1094 }
1095 
1096 
1097 /** Get the first message from the message queue.
1098  *
1099  * This can only be called on a writing interface instance.
1100  *
1101  * @return first message in queue or NULL if there is none
1102  */
1103 Message *
1105 {
1106  if ( ! __write_access ) {
1107  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
1108  "reading instance of an interface (first).");
1109  }
1110 
1111  return __message_queue->first();
1112 }
1113 
1114 /** Erase first message from queue.
1115  * This can only be called on a writing interface instance.
1116  */
1117 void
1119 {
1120  if ( ! __write_access ) {
1121  throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
1122  "reading instance of an interface (pop).");
1123  }
1124 
1125  __message_queue->pop();
1126 }
1127 
1128 
1129 /** Get iterator over all fields of this interface instance.
1130  * @return field iterator pointing to the very first value
1131  */
1134 {
1135  return InterfaceFieldIterator(this, __fieldinfo_list);
1136 }
1137 
1138 
1139 /** Invalid iterator.
1140  * @return invalid iterator reprensenting the end.
1141  */
1144 {
1145  return InterfaceFieldIterator();
1146 }
1147 
1148 
1149 /** Get the number of fields in the interface.
1150  * @return the number of fields
1151  */
1152 unsigned int
1154 {
1155  return __num_fields;
1156 }
1157 
1158 
1159 /** Resize buffer array.
1160  * This resizes the memory region used to store data buffers.
1161  * @param num_buffers number of buffers to resize to (memory is allocated
1162  * as necessary, 0 frees the memory area).
1163  * @exception Exception thrown if resizing the memory section fails
1164  */
1165 void
1166 Interface::resize_buffers(unsigned int num_buffers)
1167 {
1168  __data_mutex->lock();
1169  if (num_buffers == 0) {
1170  if (__buffers != NULL) {
1171  free(__buffers);
1172  __buffers = NULL;
1173  __num_buffers = 0;
1174  }
1175  } else {
1176  void *tmp = realloc(__buffers, num_buffers * data_size);
1177  if (tmp == NULL) {
1178  __data_mutex->unlock();
1179  throw Exception(errno, "Resizing buffers for interface %s failed", __uid);
1180  } else {
1181  __buffers = tmp;
1182  __num_buffers = num_buffers;
1183  }
1184  }
1185  __data_mutex->unlock();
1186 }
1187 
1188 
1189 /** Get number of buffers.
1190  * @return number of buffers
1191  */
1192 unsigned int
1194 {
1195  return __num_buffers;
1196 }
1197 
1198 
1199 /** Copy data from private memory to buffer.
1200  * @param buffer buffer number to copy to
1201  */
1202 void
1204 {
1205  if (buffer >= __num_buffers) {
1206  throw OutOfBoundsException("Buffer ID out of bounds",
1207  buffer, 0, __num_buffers);
1208  }
1209 
1210 
1211  __rwlock->lock_for_read();
1212  __data_mutex->lock();
1213 
1214  void *buf = (char *)__buffers + buffer * data_size;
1215 
1216  if ( __valid ) {
1217  memcpy(buf, __mem_data_ptr, data_size);
1218  } else {
1219  __data_mutex->unlock();
1220  __rwlock->unlock();
1221  throw InterfaceInvalidException(this, "copy_shared_to_buffer()");
1222  }
1223  __data_mutex->unlock();
1224  __rwlock->unlock();
1225 }
1226 
1227 
1228 /** Copy data from private memory to buffer.
1229  * @param buffer buffer number to copy to
1230  */
1231 void
1233 {
1234  if (buffer >= __num_buffers) {
1235  throw OutOfBoundsException("Buffer ID out of bounds",
1236  buffer, 0, __num_buffers);
1237  }
1238 
1239 
1240  __data_mutex->lock();
1241  void *buf = (char *)__buffers + buffer * data_size;
1242  memcpy(buf, data_ptr, data_size);
1243  __data_mutex->unlock();
1244 }
1245 
1246 
1247 
1248 /** Copy data from buffer to private memory.
1249  * @param buffer buffer number to copy to
1250  */
1251 void
1252 Interface::read_from_buffer(unsigned int buffer)
1253 {
1254  if (buffer >= __num_buffers) {
1255  throw OutOfBoundsException("Buffer ID out of bounds",
1256  buffer, 0, __num_buffers);
1257  }
1258 
1259  __data_mutex->lock();
1260  void *buf = (char *)__buffers + buffer * data_size;
1261  memcpy(data_ptr, buf, data_size);
1262  __data_mutex->unlock();
1263 }
1264 
1265 
1266 /** Compare buffer to private memory.
1267  * @param buffer buffer number of buffer to compare to private memory
1268  * @return returns a number less than, equal to, or greater than zero
1269  * if the shared buffer if less than, equal to, or greater than the
1270  * private buffer respectively.
1271  */
1272 int
1273 Interface::compare_buffers(unsigned int buffer)
1274 {
1275  if (buffer >= __num_buffers) {
1276  throw OutOfBoundsException("Buffer ID out of bounds",
1277  buffer, 0, __num_buffers);
1278  }
1279 
1280  __data_mutex->lock();
1281  void *buf = (char *)__buffers + buffer * data_size;
1282  int rv = memcmp(buf, data_ptr, data_size);
1283  __data_mutex->unlock();
1284 
1285  return rv;
1286 }
1287 
1288 
1289 /** Parse UID to type and ID strings.
1290  * Note that the returned values (type and id) must be freed once they are
1291  * no longer used. Also verifies lengths of the type and id strings.
1292  * @param uid UID to parse
1293  * @param type upon return contains the type part of the UID, must be freed
1294  * @param id upon return contains the ID part, must be freed
1295  */
1296 void
1297 Interface::parse_uid(const char *uid, char **type, char **id)
1298 {
1299  regex_t re;
1300  int ec = 0;
1301 // Requires in parse_uid()
1302 #define str(s) #s
1303 #define xstr(s) str(s)
1304  if ((ec = regcomp(&re,
1305  "^([a-zA-Z0-9]{1," xstr(__INTERFACE_TYPE_SIZE) "})::"
1306  "([a-zA-Z0-9 _\\.-]{1," xstr(__INTERFACE_ID_SIZE) "})$",
1307  REG_EXTENDED)) != 0) {
1308  char errbuf[1024];
1309  regerror(ec, &re, errbuf, 1024);
1310  throw Exception("Failed to created regular expression to parse UID (%s)",
1311  errbuf);
1312  }
1313  regmatch_t matches[3];
1314  if (regexec(&re, uid, 3, matches, 0) != 0) {
1315  regfree(&re);
1316  throw Exception("Failed to match UID %s, format error.", uid);
1317  }
1318 
1319  *type = strndup(&(uid[matches[1].rm_so]), matches[1].rm_eo - matches[1].rm_so);
1320  *id = strndup(&(uid[matches[2].rm_so]), matches[2].rm_eo - matches[2].rm_so);
1321 }
1322 
1323 } // end namespace fawkes
void copy_private_to_buffer(unsigned int buffer)
Copy data from private memory to buffer.
Definition: interface.cpp:1232
Interface field iterator.
virtual bool exists_writer(const Interface *interface) const =0
Check if a writer exists for the given interface.
This exception is thrown if an interface is invalid and it is attempted to call read()/write().
Definition: interface.h:74
int64_t timestamp_sec
time in seconds since Unix epoch
Definition: interface.h:213
const char * type
the type of the message
Definition: interface.h:185
virtual Message * clone() const
Clone this message.
Definition: message.cpp:419
MessageQueue::MessageIterator msgq_begin()
Get start iterator for message queue.
Definition: interface.cpp:1064
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:43
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:670
static Clock * instance()
Clock initializer.
Definition: clock.cpp:65
This exception is thrown if a write has been attempted on a read-only interface.
Definition: interface.h:61
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:972
InterfaceInvalidMessageException(const Interface *interface, const Message *message)
Constructor.
Definition: interface.cpp:90
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:99
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:811
const char * hash_printable() const
Get printable interface hash.
Definition: interface.cpp:302
void lock_for_read()
Aquire a reader lock.
void set_hash(unsigned char *ihash)
Set hash.
Definition: interface.cpp:312
Interface field info list.
Definition: types.h:51
unsigned int msgq_enqueue_copy(Message *message)
Enqueue copy of message at end of queue.
Definition: interface.cpp:869
size_t hash_size() const
Get size of interface hash.
Definition: interface.cpp:414
void set_auto_timestamping(bool enabled)
Enable or disable automated timestamping.
Definition: interface.cpp:733
MessageIterator end()
Get iterator to element beyond end of message queue list.
void msgq_unlock()
Unlock message queue.
Definition: interface.cpp:1044
void unlock()
Unlock the mutex.
Definition: mutex.cpp:135
bool operator==(Interface &comp) const
Check equality of two interfaces.
Definition: interface.cpp:613
const char * name
Name of this field.
Definition: types.h:54
interface_messageinfo_t * next
the next field, NULL if last
Definition: interface.h:186
bool is_valid() const
Check validity of interface.
Definition: interface.cpp:461
unsigned int data_size
Minimal data size to hold data storage.
Definition: interface.h:207
This is supposed to be the central clock in Fawkes.
Definition: clock.h:34
void msgq_remove(Message *message)
Remove message from queue.
Definition: interface.cpp:923
interface_fieldinfo_t * next
next field, NULL if last
Definition: types.h:57
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:292
A class for handling time.
Definition: time.h:91
A NULL pointer was supplied where not allowed.
Definition: software.h:34
virtual unsigned int num_readers(const Interface *interface) const =0
Get number of readers.
InterfaceMessageEnqueueException(const char *type, const char *id)
Constructor.
Definition: interface.cpp:73
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:495
unsigned int id() const
Get message ID.
Definition: message.cpp:197
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:80
This exception is thrown if a message has been queued in the interface which is not recognized by the...
Definition: interface.h:67
bool msgq_try_lock()
Try to lock message queue.
Definition: interface.cpp:1026
unsigned int msgq_size()
Get size of message queue.
Definition: interface.cpp:956
const char * uid() const
Get unique identifier of interface.
Definition: interface.cpp:660
Interface()
Constructor.
Definition: interface.cpp:231
void * value
Current value of this field.
Definition: types.h:56
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:782
unsigned int num_fields()
Get the number of fields in the interface.
Definition: interface.cpp:1153
const Time * timestamp() const
Get timestamp of last write.
Definition: interface.cpp:691
const char * id() const
Get identifier of interface.
Definition: interface.cpp:645
void lock_for_write()
Aquire a writer lock.
void add_messageinfo(const char *name)
Add an entry to the message info list.
Definition: interface.cpp:368
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1118
bool data_changed
Indicator if data has changed.
Definition: interface.h:208
unsigned int datasize() const
Get data size.
Definition: interface.cpp:529
void * data_ptr
Pointer to local memory storage.
Definition: interface.h:206
void read_from_buffer(unsigned int buffer)
Copy data from buffer to private memory.
Definition: interface.cpp:1252
Base class for exceptions in Fawkes.
Definition: exception.h:36
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1104
InterfaceWriteDeniedException(const char *type, const char *id, const char *msg)
Constructor.
Definition: interface.cpp:55
static void parse_uid(const char *uid, char **type, char **id)
Parse UID to type and ID strings.
Definition: interface.cpp:1297
void set_clock(Clock *clock)
Set clock for this instance.
Definition: time.cpp:329
virtual bool message_valid(const Message *message) const =0
Check if the message is valid and can be enqueued.
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
unsigned int mem_serial() const
Get memory serial of interface.
Definition: interface.cpp:680
void flush()
Delete all messages from queue.
virtual ~Interface()
Destructor.
Definition: interface.cpp:260
int64_t timestamp_usec
additional time microseconds
Definition: interface.h:214
Message queue used in interfaces.
Definition: message_queue.h:42
InterfaceInvalidException(const Interface *interface, const char *method)
Constructor.
Definition: interface.cpp:108
interface_fieldtype_t type
type of this field
Definition: types.h:52
void copy_shared_to_buffer(unsigned int buffer)
Copy data from private memory to buffer.
Definition: interface.cpp:1203
unsigned int num_buffers() const
Get number of buffers.
Definition: interface.cpp:1193
bool try_lock()
Try to lock message queue.
void get_timestamp(long &sec, long &usec) const
Get time stamp.
Definition: time.h:114
void add_fieldinfo(interface_fieldtype_t type, const char *name, size_t length, void *value, const char *enumtype=0)
Add an entry to the field info list.
Definition: interface.cpp:332
size_t length
Length of field (array, string)
Definition: types.h:55
virtual void notify_of_data_change(const Interface *interface)=0
Notify of data change.
bool changed() const
Check if data has been changed.
Definition: interface.cpp:748
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:830
MessageIterator begin()
Get iterator to first element in message queue.
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: interface.cpp:1143
void set_time(const timeval *tv)
Sets the time.
Definition: time.cpp:262
bool oftype(const char *interface_type) const
Check if interface is of given type.
Definition: interface.cpp:625
void set_clock(Clock *clock)
Set clock to use for timestamping.
Definition: interface.cpp:722
void resize_buffers(unsigned int num_buffers)
Resize buffer array.
Definition: interface.cpp:1166
const char * enumtype
text representation of enum type
Definition: types.h:53
bool empty() const
Check if message queue is empty.
void msgq_flush()
Flush all messages.
Definition: interface.cpp:988
void append(Message *msg)
Append message to queue.
void msgq_lock()
Lock message queue.
Definition: interface.cpp:1006
int compare_buffers(unsigned int buffer)
Compare buffer to private memory.
Definition: interface.cpp:1273
void set_validity(bool valid)
Mark this interface invalid.
Definition: interface.cpp:449
virtual void transmit(Message *message)=0
Transmit message.
void lock()
Lock this mutex.
Definition: mutex.cpp:89
Time & stamp()
Set this time to the current time.
Definition: time.cpp:783
void remove(const Message *msg)
Remove message from queue.
void unlock()
Release the lock.
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:435
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:425
void pop()
Erase first message from queue.
void unlock()
Unlock message queue.
interface_data_ts_t * data_ts
Pointer to data casted to timestamp struct.
Definition: interface.h:216
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: interface.cpp:1133
Message * first()
Get first message from queue.
Mutex mutual exclusion lock.
Definition: mutex.h:32
Index out of bounds.
Definition: software.h:88
void set_from_chunk(void *chunk)
Set from a raw data chunk.
Definition: interface.cpp:765
unsigned int size() const
Get number of messages in queue.
void lock()
Lock message queue.
This exception is thrown if a write has been attempted on a read-only interface.
Definition: interface.h:55
interface_fieldtype_t
Interface field type.
Definition: types.h:33
const char * type() const
Get type of interface.
Definition: interface.cpp:635
void set_timestamp(const Time *t=NULL)
Set timestamp.
Definition: interface.cpp:702
std::list< const char * > get_message_types()
Obtain a list of textual representations of the message types available for this interface.
Definition: interface.cpp:395
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:217
MessageQueue::MessageIterator msgq_end()
Get end iterator for message queue.
Definition: interface.cpp:1085