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