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