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
fawkes::Mutex::lock
void lock()
Lock this mutex.
Definition: mutex.cpp:87
fawkes::MessageQueue::empty
bool empty() const
Check if message queue is empty.
Definition: message_queue.cpp:238
fawkes::Interface::get_message_types
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
fawkes::RefCount::unref
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
fawkes::InterfaceMediator::exists_writer
virtual bool exists_writer(const Interface *interface) const =0
Check if a writer exists for the given interface.
fawkes::Interface::data_ptr
void * data_ptr
Pointer to local memory storage.
Definition: interface.h:224
fawkes::Interface::datachunk
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:429
fawkes::InterfaceInvalidMessageException
This exception is thrown if a message has been queued in the interface which is not recognized by the...
Definition: interface.h:67
fawkes::Interface::set_validity
void set_validity(bool valid)
Mark this interface invalid.
Definition: interface.cpp:451
fawkes::Interface::msgq_end
MessageQueue::MessageIterator msgq_end()
Get end iterator for message queue.
Definition: interface.cpp:1148
fawkes::InterfaceMediator::notify_of_data_change
virtual void notify_of_data_change(const Interface *interface)=0
Notify of data change.
fawkes::Interface::interface_messageinfo_t::type
const char * type
the type of the message
Definition: interface.h:191
fawkes::Interface::interface_messageinfo_t
Message info list.
Definition: interface.h:190
fawkes::Interface::msgq_pop
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1182
fawkes::Time::set_time
void set_time(const timeval *tv)
Sets the time.
Definition: time.cpp:246
fawkes::Interface::msgq_empty
bool msgq_empty()
Check if queue is empty.
Definition: interface.cpp:1029
fawkes::interface_fieldinfo_t::next
interface_fieldinfo_t * next
next field, NULL if last
Definition: types.h:65
fawkes::MessageQueue::try_lock
bool try_lock()
Try to lock message queue.
Definition: message_queue.cpp:266
fawkes::Interface::interface_messageinfo_t::next
interface_messageinfo_t * next
the next field, NULL if last
Definition: interface.h:192
fawkes::Interface::fields_end
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: interface.cpp:1207
fawkes::MessageQueue
Message queue used in interfaces.
Definition: message_queue.h:42
fawkes::MessageQueue::flush
void flush()
Delete all messages from queue.
Definition: message_queue.cpp:74
fawkes::Interface::compare_buffers
int compare_buffers(unsigned int buffer)
Compare buffer to private memory.
Definition: interface.cpp:1327
fawkes::Mutex
Mutex mutual exclusion lock.
Definition: mutex.h:33
fawkes::Interface::timestamp
const Time * timestamp() const
Get timestamp of last write.
Definition: interface.cpp:705
fawkes::interface_fieldtype_t
interface_fieldtype_t
Interface field type.
Definition: types.h:36
fawkes::InterfaceMediator::writer
virtual std::string writer(const Interface *interface) const =0
Get writer of interface.
fawkes::Interface::is_writer
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:438
fawkes::Message
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:45
fawkes::Interface::hash_printable
const char * hash_printable() const
Get printable interface hash.
Definition: interface.cpp:307
fawkes::Interface::read
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
fawkes::Message::set_id
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:198
fawkes::Interface::interface_data_ts_t
Timestamp data, must be present and first entries for each interface data structs!...
Definition: interface.h:198
fawkes::Interface::hash
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:298
fawkes::Interface::read_from_buffer
void read_from_buffer(unsigned int buffer)
Copy data from buffer to private memory.
Definition: interface.cpp:1305
fawkes::MutexLocker
Mutex locking helper.
Definition: mutex_locker.h:34
fawkes::MessageQueue::lock
void lock()
Lock message queue.
Definition: message_queue.cpp:253
fawkes::Interface::message_valid
virtual bool message_valid(const Message *message) const =0
Check if the message is valid and can be enqueued.
fawkes::MessageQueue::pop
void pop()
Erase first message from queue.
Definition: message_queue.cpp:295
fawkes::MessageQueue::unlock
void unlock()
Unlock message queue.
Definition: message_queue.cpp:274
fawkes::Interface::type
const char * type() const
Get type of interface.
Definition: interface.cpp:643
fawkes::InterfaceInvalidException::InterfaceInvalidException
InterfaceInvalidException(const Interface *interface, const char *method)
Constructor.
Definition: interface.cpp:110
fawkes::Interface::msgq_remove
void msgq_remove(Message *message)
Remove message from queue.
Definition: interface.cpp:977
fawkes::Interface::add_fieldinfo
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
fawkes::Interface::set_clock
void set_clock(Clock *clock)
Set clock to use for timestamping.
Definition: interface.cpp:736
fawkes::InterfaceInvalidMessageException::InterfaceInvalidMessageException
InterfaceInvalidMessageException(const Interface *interface, const Message *message)
Constructor.
Definition: interface.cpp:92
fawkes::Interface::interface_data_ts_t::timestamp_sec
int64_t timestamp_sec
time in seconds since Unix epoch
Definition: interface.h:199
fawkes::Interface::id
const char * id() const
Get identifier of interface.
Definition: interface.cpp:652
fawkes::Mutex::unlock
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
fawkes::Interface::data_ts
interface_data_ts_t * data_ts
Pointer to data casted to timestamp struct.
Definition: interface.h:228
fawkes::Interface::mem_serial
unsigned int mem_serial() const
Get memory serial of interface.
Definition: interface.cpp:695
fawkes::OutOfBoundsException
Index out of bounds.
Definition: software.h:86
fawkes::Interface::interface_data_ts_t::timestamp_usec
int64_t timestamp_usec
additional time microseconds
Definition: interface.h:200
fawkes::Interface::set_timestamp
void set_timestamp(const Time *t=NULL)
Set timestamp.
Definition: interface.cpp:715
fawkes::ReadWriteLock::lock_for_read
void lock_for_read()
Aquire a reader lock.
Definition: read_write_lock.cpp:93
fawkes::Interface::mark_data_changed
void mark_data_changed()
Mark data as changed.
Definition: interface.cpp:758
fawkes::MessageQueue::size
unsigned int size() const
Get number of messages in queue.
Definition: message_queue.cpp:220
fawkes::InterfaceWriteDeniedException::InterfaceWriteDeniedException
InterfaceWriteDeniedException(const char *type, const char *id, const char *msg)
Constructor.
Definition: interface.cpp:54
fawkes::MessageMediator::transmit
virtual void transmit(Message *message)=0
Transmit message.
fawkes::MessageQueue::end
MessageIterator end()
Get iterator to element beyond end of message queue list.
Definition: message_queue.cpp:323
fawkes::Interface::data_changed
bool data_changed
Indicator if data has changed.
Definition: interface.h:226
fawkes::InterfaceFieldIterator
Interface field iterator.
Definition: field_iterator.h:39
fawkes::Interface::writer
std::string writer() const
Get owner name of writing interface instance.
Definition: interface.cpp:855
fawkes::InterfaceMediator::num_readers
virtual unsigned int num_readers(const Interface *interface) const =0
Get number of readers.
fawkes::RefCount::ref
void ref()
Increment reference count.
Definition: refcount.cpp:67
fawkes::Interface::Interface
Interface()
Constructor.
Definition: interface.cpp:233
fawkes::Interface::msgq_lock
void msgq_lock()
Lock message queue.
Definition: interface.cpp:1065
fawkes
Fawkes library namespace.
fawkes::interface_fieldinfo_t::enumtype
const char * enumtype
text representation of enum type
Definition: types.h:60
fawkes::Interface::buffer_timestamp
Time buffer_timestamp(unsigned int buffer)
Get time of a buffer.
Definition: interface.cpp:1346
fawkes::Interface::changed
bool changed() const
Check if data has been changed.
Definition: interface.cpp:780
fawkes::Interface::set_hash
void set_hash(unsigned char *ihash)
Set hash.
Definition: interface.cpp:316
fawkes::Interface::readers
std::list< std::string > readers() const
Get owner names of reading interface instances.
Definition: interface.cpp:864
fawkes::interface_fieldinfo_t
Interface field info list.
Definition: types.h:58
fawkes::MessageQueue::append
void append(Message *msg)
Append message to queue.
Definition: message_queue.cpp:96
fawkes::MessageQueue::MessageIterator
Message iterator.
Definition: message_queue.h:59
fawkes::Interface::msgq_begin
MessageQueue::MessageIterator msgq_begin()
Get start iterator for message queue.
Definition: interface.cpp:1126
fawkes::MessageQueue::remove
void remove(const Message *msg)
Remove message from queue.
Definition: message_queue.cpp:157
fawkes::ReadWriteLock::lock_for_write
void lock_for_write()
Aquire a writer lock.
Definition: read_write_lock.cpp:104
fawkes::InterfaceMediator::readers
virtual std::list< std::string > readers(const Interface *interface) const =0
Get owners of interfaces who opened for reading.
fawkes::Interface::msgq_append
void msgq_append(Message *message)
Enqueue message.
Definition: interface.cpp:953
fawkes::Interface::msgq_enqueue_copy
unsigned int msgq_enqueue_copy(Message *message)
Enqueue copy of message at end of queue.
Definition: interface.cpp:920
fawkes::Interface
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
fawkes::Interface::resize_buffers
void resize_buffers(unsigned int num_buffers)
Resize buffer array.
Definition: interface.cpp:1228
fawkes::Interface::has_writer
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:817
fawkes::Time::set_clock
void set_clock(Clock *clock)
Set clock for this instance.
Definition: time.cpp:308
fawkes::MessageQueue::first
Message * first()
Get first message from queue.
Definition: message_queue.cpp:283
fawkes::Interface::msgq_unlock
void msgq_unlock()
Unlock message queue.
Definition: interface.cpp:1104
fawkes::Interface::num_buffers
unsigned int num_buffers() const
Get number of buffers.
Definition: interface.cpp:1254
fawkes::interface_fieldinfo_t::enum_map
const interface_enum_map_t * enum_map
Map of possible enum values.
Definition: types.h:64
fawkes::Interface::parse_uid
static void parse_uid(const char *uid, std::string &type, std::string &id)
Parse UID to type and ID strings.
Definition: interface.cpp:1387
fawkes::InterfaceWriteDeniedException
This exception is thrown if a write has been attempted on a read-only interface.
Definition: interface.h:55
fawkes::interface_enum_map_t
std::map< int, std::string > interface_enum_map_t
Map of enum integer to string values.
Definition: types.h:54
fawkes::ReadWriteLock::unlock
void unlock()
Release the lock.
Definition: read_write_lock.cpp:137
fawkes::Interface::uid
const char * uid() const
Get unique identifier of interface.
Definition: interface.cpp:677
fawkes::interface_fieldinfo_t::name
const char * name
Name of this field.
Definition: types.h:61
fawkes::Interface::num_readers
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:845
fawkes::Interface::fields
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: interface.cpp:1198
fawkes::Time
A class for handling time.
Definition: time.h:93
fawkes::Interface::owner
const char * owner() const
Get owner of interface.
Definition: interface.cpp:663
fawkes::Interface::set_auto_timestamping
void set_auto_timestamping(bool enabled)
Enable or disable automated timestamping.
Definition: interface.cpp:746
fawkes::Interface::data_size
unsigned int data_size
Minimal data size to hold data storage.
Definition: interface.h:225
fawkes::interface_fieldinfo_t::length
size_t length
Length of field (array, string)
Definition: types.h:62
fawkes::Interface::serial
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:686
fawkes::Interface::msgq_size
unsigned int msgq_size()
Get size of message queue.
Definition: interface.cpp:1012
fawkes::Interface::num_fields
unsigned int num_fields()
Get the number of fields in the interface.
Definition: interface.cpp:1216
fawkes::Message::clone
virtual Message * clone() const
Clone this message.
Definition: message.cpp:383
fawkes::Message::id
unsigned int id() const
Get message ID.
Definition: message.cpp:180
fawkes::Clock::instance
static Clock * instance()
Clock initializer.
Definition: clock.cpp:63
fawkes::Time::stamp
Time & stamp()
Set this time to the current time.
Definition: time.cpp:704
fawkes::Interface::~Interface
virtual ~Interface()
Destructor.
Definition: interface.cpp:262
fawkes::Interface::copy_private_to_buffer
void copy_private_to_buffer(unsigned int buffer)
Copy data from private memory to buffer.
Definition: interface.cpp:1289
fawkes::Interface::msgq_flush
void msgq_flush()
Flush all messages.
Definition: interface.cpp:1046
fawkes::Interface::datasize
unsigned int datasize() const
Get data size.
Definition: interface.cpp:531
fawkes::NullPointerException
A NULL pointer was supplied where not allowed.
Definition: software.h:32
fawkes::InterfaceMessageEnqueueException
This exception is thrown if a write has been attempted on a read-only interface.
Definition: interface.h:61
fawkes::Interface::msgq_enqueue
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:882
fawkes::Interface::oftype
bool oftype(const char *interface_type) const
Check if interface is of given type.
Definition: interface.cpp:634
fawkes::Interface::set_from_chunk
void set_from_chunk(void *chunk)
Set from a raw data chunk.
Definition: interface.cpp:800
fawkes::Time::get_timestamp
void get_timestamp(long &sec, long &usec) const
Get time stamp.
Definition: time.h:137
fawkes::InterfaceMessageEnqueueException::InterfaceMessageEnqueueException
InterfaceMessageEnqueueException(const char *type, const char *id)
Constructor.
Definition: interface.cpp:74
fawkes::Interface::msgq_first
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1167
fawkes::Interface::add_messageinfo
void add_messageinfo(const char *name)
Add an entry to the message info list.
Definition: interface.cpp:375
fawkes::Interface::write
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:494
fawkes::interface_fieldinfo_t::type
interface_fieldtype_t type
type of this field
Definition: types.h:59
fawkes::Interface::hash_size
size_t hash_size() const
Get size of interface hash.
Definition: interface.cpp:419
fawkes::InterfaceInvalidException
This exception is thrown if an interface is invalid and it is attempted to call read()/write().
Definition: interface.h:73
fawkes::Interface::is_valid
bool is_valid() const
Check validity of interface.
Definition: interface.cpp:462
fawkes::Interface::copy_shared_to_buffer
void copy_shared_to_buffer(unsigned int buffer)
Copy data from private memory to buffer.
Definition: interface.cpp:1263
fawkes::MessageQueue::begin
MessageIterator begin()
Get iterator to first element in message queue.
Definition: message_queue.cpp:309
fawkes::Clock
This is supposed to be the central clock in Fawkes.
Definition: clock.h:35
fawkes::Interface::msgq_try_lock
bool msgq_try_lock()
Try to lock message queue.
Definition: interface.cpp:1086
fawkes::Interface::operator==
bool operator==(Interface &comp) const
Check equality of two interfaces.
Definition: interface.cpp:623
fawkes::interface_fieldinfo_t::value
void * value
Current value of this field.
Definition: types.h:63
fawkes::Exception
Base class for exceptions in Fawkes.
Definition: exception.h:36