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  if (valid_) {
503  if (data_changed) {
504  if (auto_timestamping_)
505  timestamp_->stamp();
506  long sec = 0, usec = 0;
507  timestamp_->get_timestamp(sec, usec);
508  data_ts->timestamp_sec = sec;
509  data_ts->timestamp_usec = usec;
510  data_changed = false;
511  }
512  memcpy(mem_data_ptr_, data_ptr, data_size);
513  } else {
514  data_mutex_->unlock();
515  rwlock_->unlock();
516  throw InterfaceInvalidException(this, "write()");
517  }
518  data_mutex_->unlock();
519  rwlock_->unlock();
520 
521  interface_mediator_->notify_of_data_change(this);
522 }
523 
524 /** Get data size.
525  * @return size in bytes of data segment
526  */
527 unsigned int
529 {
530  return data_size;
531 }
532 
533 /** Set type, ID and UID.
534  * Sets type and ID, UID is generated automatically as Type::ID.
535  * @param type string, a maximum of INTERFACE_TYPE_SIZE_ bytes are copied
536  * @param ID string, a maximum of INTERFACE_ID_SIZE_ bytes are copied
537  */
538 void
539 Interface::set_type_id(const char *type, const char *id)
540 {
541  strncpy(type_, type, INTERFACE_TYPE_SIZE_);
542  strncpy(id_, id, INTERFACE_ID_SIZE_);
543  snprintf(uid_, INTERFACE_UID_SIZE_ + 1, "%s::%s", type_, id_);
544  // Enforce null-terminated strings. If the input was not properly
545  // null-terminated, this truncated the last character of the string.
546  type_[INTERFACE_TYPE_SIZE_] = 0;
547  id_[INTERFACE_ID_SIZE_] = 0;
548  uid_[INTERFACE_UID_SIZE_] = 0;
549 }
550 
551 /** Set instance serial.
552  * @param instance_serial instance serial
553  */
554 void
555 Interface::set_instance_serial(unsigned short instance_serial)
556 {
557  instance_serial_ = instance_serial;
558 }
559 
560 /** Set mediators.
561  * @param iface_mediator interface mediator
562  * @param msg_mediator message mediator.
563  */
564 void
565 Interface::set_mediators(InterfaceMediator *iface_mediator, MessageMediator *msg_mediator)
566 {
567  interface_mediator_ = iface_mediator;
568  message_mediator_ = msg_mediator;
569 }
570 
571 /** Set memory data.
572  * @param serial mem serial
573  * @param real_ptr pointer to whole chunk
574  * @param data_ptr pointer to data chunk
575  */
576 void
577 Interface::set_memory(unsigned int serial, void *real_ptr, void *data_ptr)
578 {
579  mem_serial_ = serial;
580  mem_real_ptr_ = real_ptr;
581  mem_data_ptr_ = data_ptr;
582 }
583 
584 /** Set read/write info.
585  * @param write_access true to enable write access, false for read-only
586  * @param rwlock read/write lock for this interface
587  */
588 void
589 Interface::set_readwrite(bool write_access, RefCountRWLock *rwlock)
590 {
591  write_access_ = write_access;
592  rwlock_ = rwlock;
593 }
594 
595 /** Set owner name for interface.
596  * @param owner name of owner of interface
597  */
598 void
599 Interface::set_owner(const char *owner)
600 {
601  if (owner_)
602  free(owner_);
603  owner_ = NULL;
604  if (owner)
605  owner_ = strdup(owner);
606 }
607 
608 /** Check equality of two interfaces.
609  * Two interfaces are the same if their types and identifiers are
610  * equal. This does not mean that both interfaces are the very same
611  * instance for accessing the BlackBoard. Instead this just means that
612  * both instances will access the same chunk of memory in the
613  * BlackBoard and the instances MAY be the same. If you want to know
614  * if two instances are exactly the same compare the instance serials
615  * using the serial() method.
616  * @param comp interface to compare current instance with
617  * @return true, if interfaces point to the same data, false otherwise
618  */
619 bool
621 {
622  return ((strncmp(type_, comp.type_, sizeof(type_)) == 0)
623  && (strncmp(id_, comp.id_, sizeof(id_)) == 0));
624 }
625 
626 /** Check if interface is of given type.
627  * @param interface_type type to query
628  * @return true, if current instance is of given type, false otherwise
629  */
630 bool
631 Interface::oftype(const char *interface_type) const
632 {
633  return (strncmp(this->type_, interface_type, sizeof(this->type_)) == 0);
634 }
635 
636 /** Get type of interface.
637  * @return string with the type of the interface.
638  */
639 const char *
641 {
642  return type_;
643 }
644 
645 /** Get identifier of interface.
646  * @return string with the identifier of the interface.
647  */
648 const char *
650 {
651  return id_;
652 }
653 
654 /** Get owner of interface.
655  * The owner is an arbitrary name, usually a thread or plugin name
656  * for the entity which opened this specific interface instance.
657  * @return owner name
658  */
659 const char *
661 {
662  return owner_;
663 }
664 
665 /** Get unique identifier of interface.
666  * As the name suggests this ID denotes a unique memory instance of
667  * this interface in the blackboard. It is provided by the system and
668  * currently returns a string of the form "type::id", where type is
669  * replaced by the type returned by type() and id is the ID returned
670  * by id().
671  * @return string with the unique identifier of the interface.
672  */
673 const char *
675 {
676  return uid_;
677 }
678 
679 /** Get instance serial of interface.
680  * @return instance serial of the interface.
681  */
682 unsigned short
684 {
685  return instance_serial_;
686 }
687 
688 /** Get memory serial of interface.
689  * @return memory serial of interface
690  */
691 unsigned int
693 {
694  return mem_serial_;
695 }
696 
697 /** Get timestamp of last write.
698  * Note that you need to call read() before this provides useful information.
699  * @return timestamp of last write.
700  */
701 const Time *
703 {
704  return timestamp_;
705 }
706 
707 /** Set timestamp.
708  * @param t time stamp to copy time from, if NULL current time is queried
709  * from clock.
710  */
711 void
713 {
714  if (auto_timestamping_)
715  throw Exception("Auto timestamping enabled, cannot "
716  "set explicit timestamp");
717  if (!write_access_)
718  throw Exception("Timestamp can only be set on writing "
719  "instance");
720 
721  if (t) {
722  *timestamp_ = t;
723  } else {
724  timestamp_->stamp();
725  }
726  data_changed = true;
727 }
728 
729 /** Set clock to use for timestamping.
730  * @param clock clock to use from now on
731  */
732 void
734 {
735  clock_ = clock;
736  timestamp_->set_clock(clock);
737 }
738 
739 /** Enable or disable automated timestamping.
740  * @param enabled true to enable automated timestamping, false to disable
741  */
742 void
744 {
745  auto_timestamping_ = enabled;
746 }
747 
748 /** Mark data as changed.
749  * This m will mark the data as changed for a writing instance. One the
750  * next write, the data will be written with an updated timestamp (if
751  * auto timestamping is enabled), irregardless of whether new data was
752  * actually set.
753  */
754 void
756 {
757  data_changed = true;
758 }
759 
760 /** Check if data has been changed.
761  * This method has slightly different semantics depending on whether
762  * this interface is a writing or a reading instance.
763  * For a reading instance:
764  * Note that if the data has been modified this method will return
765  * true at least until the next call to read. From then on it will
766  * return false if the data has not been modified between the two
767  * read() calls and still true otherwise.
768  * For a writing instance:
769  * The data is considered to have changed if any of the interface field
770  * set methods has been called since the last write() call.
771  * @return true if data has been changed between the last call to
772  * read() and the one before (reading instance) or if any data field
773  * setter has been called since the last write() call (writing instance),
774  * false otherwise
775  */
776 bool
778 {
779  if (write_access_) {
780  return data_changed;
781  } else {
782  return (*timestamp_ != local_read_timestamp_);
783  }
784 }
785 
786 /** Set from a raw data chunk.
787  * This allows for setting the interface data from a raw chunk. This
788  * is not useful in general but only in rare situations like network
789  * transmission. Do not use it unless you really know what you are
790  * doing. The method expects the chunk to be exactly of the size
791  * returned by datasize(). No check is done, a segfault will most
792  * likely occur if you provide invalid data.
793  * @param chunk data chunk, must be exactly of the size that is
794  * returned by datasize()
795  */
796 void
798 {
799  // This could be checked but should never happen with our generated
800  // interfaces anyway
801  // if ( data_ptr == NULL )
802  // throw NullPointerException("Interface not initialized");
803 
804  memcpy(data_ptr, chunk, data_size);
805 }
806 
807 /** Check if there is a writer for the interface.
808  * Use this method to determine if there is any open instance of the
809  * interface that is writing to the interface. This can also be the
810  * queried interface instance.
811  * @return true if a writer for the interface exists, false otherwise
812  */
813 bool
815 {
816  return interface_mediator_->exists_writer(this);
817 }
818 
819 /** Get the number of readers.
820  * Use this method to determine how many reading instances of the
821  * interface currently exist. If the current instance is a reading
822  * instance it will be included in the count number. To determine if
823  * you are the last man having this interface you can use the
824  * following code:
825  * @code
826  * // for a writing instance:
827  * if ( interface->num_readers == 0 ) {
828  * // we are the last one to have this interface open
829  * }
830  *
831  * // for a reading instance:
832  * if ( ! interface->has_writer() && (interface->num_readers() == 0) ) {
833  * // we are the last one to have this interface open
834  * }
835  * @endcode
836  * Note that this can result in a race condition. You have to be
837  * registered as a BlackBoardEventListener to be sure that you are
838  * really the last.
839  * @return number of readers
840  */
841 unsigned int
843 {
844  return interface_mediator_->num_readers(this);
845 }
846 
847 /** Get owner name of writing interface instance.
848  * @return name of owner of writing interface instance if a local one
849  * exists, an empty string otherwise.
850  */
851 std::string
853 {
854  return interface_mediator_->writer(this);
855 }
856 
857 /** Get owner names of reading interface instances.
858  * @return list of names of owners of instances opened for reading
859  */
860 std::list<std::string>
862 {
863  return interface_mediator_->readers(this);
864 }
865 
866 /** Enqueue message at end of queue.
867  * This appends the given message to the queue and transmits the
868  * message via the message mediator. The message is afterwards owned
869  * by the other side and will be unrefed and freed as soon as it has
870  * been processed. If you want to keep this message to read a feedback
871  * status you have to reference it _before_ enqueuing it!
872  * This can only be called on a reading interface instance.
873  * @param message Message to enqueue.
874  * @return message id after message has been queued
875  * @exception MessageAlreadyQueuedException thrown if the message has
876  * already been enqueued to an interface.
877  */
878 unsigned int
880 {
881  if (write_access_) {
882  throw InterfaceMessageEnqueueException(type_, id_);
883  }
884 
885  if (message_valid(message)) {
886  message->set_interface(this);
887  message->set_id(next_msg_id());
888  // transmit might change the message id!
889  message_mediator_->transmit(message);
890  unsigned int msgid = message->id();
891  message->unref();
892  return msgid;
893  } else {
894  throw InterfaceInvalidMessageException(this, message);
895  }
896 }
897 
898 /** Enqueue copy of message at end of queue.
899 
900  * This method creates a copy of the message and enqueues it. Note
901  * that this way you cannot receive status message in the message,
902  * because the other side will not use your message instance but a
903  * copy instead.
904  *
905  * This is particularly useful if you call from an environment with
906  * automatic garbage collection that does not honor the referencing
907  * feature of message but rather just deletes it.
908  *
909  * This can only be called on a reading interface instance.
910  *
911  * @param message Message to enqueue.
912  * @return message id after message has been queued
913  * @exception MessageAlreadyQueuedException thrown if the message has already been
914  * enqueued to an interface.
915  */
916 unsigned int
918 {
919  if (write_access_) {
920  throw InterfaceMessageEnqueueException(type_, id_);
921  }
922  if (message == NULL) {
923  throw NullPointerException("Message may not be NULL");
924  }
925 
926  if (message_valid(message)) {
927  Message *mcopy = message->clone();
928  mcopy->set_interface(this);
929  mcopy->set_id(next_msg_id());
930  message_mediator_->transmit(mcopy);
931  unsigned int msgid = mcopy->id();
932  mcopy->unref();
933  message->set_id(msgid);
934  return msgid;
935  } else {
936  throw InterfaceInvalidMessageException(this, message);
937  }
938 }
939 
940 /** Enqueue message.
941  * This will enqueue the message without transmitting it via the
942  * message mediator. It can be useful, for example, to enqueue the
943  * message from an event callback.
944  *
945  * This can only be called on a writing interface instance.
946  *
947  * @param message message to enqueue, reference count will be incremented.
948  */
949 void
951 {
952  if (!write_access_) {
953  throw InterfaceWriteDeniedException(type_,
954  id_,
955  "Cannot work on message queue on "
956  "reading instance of an interface (append).");
957  }
958 
959  message->ref();
960  message_queue_->append(message);
961 }
962 
963 /** Remove message from queue.
964  * Removes the given message from the queue. Note that if you
965  * unref()ed the message after insertion this will most likely delete
966  * the object. It is not safe to use the message after removing it
967  * from the queue in general.
968  *
969  * This can only be called on a writing interface instance.
970  *
971  * @param message Message to remove.
972  */
973 void
975 {
976  if (!write_access_) {
977  throw InterfaceWriteDeniedException(type_,
978  id_,
979  "Cannot work on message queue on "
980  "reading instance of an interface (remove msg).");
981  }
982 
983  return message_queue_->remove(message);
984 }
985 
986 /** Remove message from queue.
987  * Removes message with the given ID from the queue.
988  * @param message_id Message ID to remove.
989  * This can only be called on a writing interface instance.
990  */
991 void
992 Interface::msgq_remove(unsigned int message_id)
993 {
994  if (!write_access_) {
995  throw InterfaceWriteDeniedException(type_,
996  id_,
997  "Cannot work on message queue on "
998  "reading instance of an interface (remove id).");
999  }
1000 
1001  return message_queue_->remove(message_id);
1002 }
1003 
1004 /** Get size of message queue.
1005  * This can only be called on a writing interface instance.
1006  * @return number of messages in queue.
1007  */
1008 unsigned int
1010 {
1011  if (!write_access_) {
1012  throw InterfaceWriteDeniedException(type_,
1013  id_,
1014  "Cannot work on message queue on "
1015  "reading instance of an interface (size).");
1016  }
1017 
1018  return message_queue_->size();
1019 }
1020 
1021 /** Check if queue is empty.
1022  * This can only be called on a writing interface instance.
1023  * @return true if queue is empty, false otherwise
1024  */
1025 bool
1027 {
1028  if (!write_access_) {
1029  throw InterfaceWriteDeniedException(type_,
1030  id_,
1031  "Cannot work on message queue on "
1032  "reading instance of an interface (empty).");
1033  }
1034 
1035  return message_queue_->empty();
1036 }
1037 
1038 /** Flush all messages.
1039  * Deletes all messages from the queue.
1040  * This can only be called on a writing interface instance.
1041  */
1042 void
1044 {
1045  if (!write_access_) {
1046  throw InterfaceWriteDeniedException(type_,
1047  id_,
1048  "Cannot work on message queue on "
1049  "reading instance of an interface (flush).");
1050  }
1051 
1052  message_queue_->flush();
1053 }
1054 
1055 /** Lock message queue.
1056  * Lock the message queue. You have to do this * before using the
1057  * iterator safely.
1058  *
1059  * This can only be called on a writing interface instance.
1060  */
1061 void
1063 {
1064  if (!write_access_) {
1065  throw InterfaceWriteDeniedException(type_,
1066  id_,
1067  "Cannot work on message queue on "
1068  "reading instance of an interface (lock).");
1069  }
1070 
1071  message_queue_->lock();
1072 }
1073 
1074 /** Try to lock message queue.
1075  * Try to lock the message queue. Returns immediately and does not
1076  * wait for lock.
1077  *
1078  * This can only be called on a writing interface instance.
1079  * @return true, if the lock has been aquired, false otherwise.
1080  * @see lock()
1081  */
1082 bool
1084 {
1085  if (!write_access_) {
1086  throw InterfaceWriteDeniedException(type_,
1087  id_,
1088  "Cannot work on message queue on "
1089  "reading instance of an interface "
1090  "(msgq_try_lock).");
1091  }
1092 
1093  return message_queue_->try_lock();
1094 }
1095 
1096 /** Unlock message queue.
1097  * Give free the lock on the message queue.
1098  * This can only be called on a writing interface instance.
1099  */
1100 void
1102 {
1103  if (!write_access_) {
1104  throw InterfaceWriteDeniedException(type_,
1105  id_,
1106  "Cannot work on message queue on "
1107  "reading instance of an interface (unlock).");
1108  }
1109 
1110  message_queue_->unlock();
1111 }
1112 
1113 /** Get start iterator for message queue.
1114  * Not that you must have locked the queue before this operation!
1115  *
1116  * This can only be called on a writing interface instance.
1117  *
1118  * @return iterator to begin of message queue.
1119  * @exception NotLockedException thrown if message queue is not locked
1120  * during this operation.
1121  */
1124 {
1125  if (!write_access_) {
1126  throw InterfaceWriteDeniedException(type_,
1127  id_,
1128  "Cannot work on message queue on "
1129  "reading instance of an interface (begin).");
1130  }
1131 
1132  return message_queue_->begin();
1133 }
1134 
1135 /** Get end iterator for message queue.
1136  * Not that you must have locked the queue before this operation!
1137  *
1138  * This can only be called on a writing interface instance.
1139  *
1140  * @return iterator beyond end of message queue.
1141  * @exception NotLockedException thrown if message queue is not locked
1142  * during this operation.
1143  */
1146 {
1147  if (!write_access_) {
1148  throw InterfaceWriteDeniedException(type_,
1149  id_,
1150  "Cannot work on message queue on "
1151  "reading instance of an interface (end).");
1152  }
1153 
1154  return message_queue_->end();
1155 }
1156 
1157 /** Get the first message from the message queue.
1158  *
1159  * This can only be called on a writing interface instance.
1160  *
1161  * @return first message in queue or NULL if there is none
1162  */
1163 Message *
1165 {
1166  if (!write_access_) {
1167  throw InterfaceWriteDeniedException(type_,
1168  id_,
1169  "Cannot work on message queue on "
1170  "reading instance of an interface (first).");
1171  }
1172  return message_queue_->first();
1173 }
1174 
1175 /** Erase first message from queue.
1176  * This can only be called on a writing interface instance.
1177  */
1178 void
1180 {
1181  if (!write_access_) {
1182  throw InterfaceWriteDeniedException(type_,
1183  id_,
1184  "Cannot work on message queue on "
1185  "reading instance of an interface (pop).");
1186  }
1187 
1188  message_queue_->pop();
1189 }
1190 
1191 /** Get iterator over all fields of this interface instance.
1192  * @return field iterator pointing to the very first value
1193  */
1196 {
1197  return InterfaceFieldIterator(this, fieldinfo_list_);
1198 }
1199 
1200 /** Invalid iterator.
1201  * @return invalid iterator reprensenting the end.
1202  */
1205 {
1206  return InterfaceFieldIterator();
1207 }
1208 
1209 /** Get the number of fields in the interface.
1210  * @return the number of fields
1211  */
1212 unsigned int
1214 {
1215  return num_fields_;
1216 }
1217 
1218 /** Resize buffer array.
1219  * This resizes the memory region used to store data buffers.
1220  * @param num_buffers number of buffers to resize to (memory is allocated
1221  * as necessary, 0 frees the memory area).
1222  * @exception Exception thrown if resizing the memory section fails
1223  */
1224 void
1225 Interface::resize_buffers(unsigned int num_buffers)
1226 {
1227  data_mutex_->lock();
1228  if (num_buffers == 0) {
1229  if (buffers_ != NULL) {
1230  free(buffers_);
1231  buffers_ = NULL;
1232  num_buffers_ = 0;
1233  }
1234  } else {
1235  void *tmp = realloc(buffers_, (size_t)num_buffers * data_size);
1236  if (tmp == NULL) {
1237  data_mutex_->unlock();
1238  throw Exception(errno, "Resizing buffers for interface %s failed", uid_);
1239  } else {
1240  buffers_ = tmp;
1241  num_buffers_ = num_buffers;
1242  }
1243  }
1244  data_mutex_->unlock();
1245 }
1246 
1247 /** Get number of buffers.
1248  * @return number of buffers
1249  */
1250 unsigned int
1252 {
1253  return num_buffers_;
1254 }
1255 
1256 /** Copy data from private memory to buffer.
1257  * @param buffer buffer number to copy to
1258  */
1259 void
1261 {
1262  if (buffer >= num_buffers_) {
1263  throw OutOfBoundsException("Buffer ID out of bounds", buffer, 0, num_buffers_);
1264  }
1265 
1266  rwlock_->lock_for_read();
1267  data_mutex_->lock();
1268 
1269  void *buf = (char *)buffers_ + buffer * data_size;
1270 
1271  if (valid_) {
1272  memcpy(buf, mem_data_ptr_, data_size);
1273  } else {
1274  data_mutex_->unlock();
1275  rwlock_->unlock();
1276  throw InterfaceInvalidException(this, "copy_shared_to_buffer()");
1277  }
1278  data_mutex_->unlock();
1279  rwlock_->unlock();
1280 }
1281 
1282 /** Copy data from private memory to buffer.
1283  * @param buffer buffer number to copy to
1284  */
1285 void
1287 {
1288  if (buffer >= num_buffers_) {
1289  throw OutOfBoundsException("Buffer ID out of bounds", buffer, 0, num_buffers_);
1290  }
1291 
1292  data_mutex_->lock();
1293  void *buf = (char *)buffers_ + buffer * data_size;
1294  memcpy(buf, data_ptr, data_size);
1295  data_mutex_->unlock();
1296 }
1297 
1298 /** Copy data from buffer to private memory.
1299  * @param buffer buffer number to copy to
1300  */
1301 void
1302 Interface::read_from_buffer(unsigned int buffer)
1303 {
1304  if (buffer >= num_buffers_) {
1305  throw OutOfBoundsException("Buffer ID out of bounds", buffer, 0, num_buffers_);
1306  }
1307 
1308  data_mutex_->lock();
1309  void *buf = (char *)buffers_ + buffer * data_size;
1310  memcpy(data_ptr, buf, data_size);
1311  *local_read_timestamp_ = *timestamp_;
1313 
1314  data_mutex_->unlock();
1315 }
1316 
1317 /** Compare buffer to private memory.
1318  * @param buffer buffer number of buffer to compare to private memory
1319  * @return returns a number less than, equal to, or greater than zero
1320  * if the shared buffer if less than, equal to, or greater than the
1321  * private buffer respectively.
1322  */
1323 int
1324 Interface::compare_buffers(unsigned int buffer)
1325 {
1326  if (buffer >= num_buffers_) {
1327  throw OutOfBoundsException("Buffer ID out of bounds", buffer, 0, num_buffers_);
1328  }
1329 
1330  data_mutex_->lock();
1331  void *buf = (char *)buffers_ + buffer * data_size;
1332  int rv = memcmp(buf, data_ptr, data_size);
1333  data_mutex_->unlock();
1334 
1335  return rv;
1336 }
1337 
1338 /** Get time of a buffer.
1339  * @param buffer buffer number
1340  * @return timestamp stored in the interface
1341  */
1342 Time
1343 Interface::buffer_timestamp(unsigned int buffer)
1344 {
1345  if (buffer >= num_buffers_) {
1346  throw OutOfBoundsException("Buffer ID out of bounds", buffer, 0, num_buffers_);
1347  }
1348 
1349  MutexLocker lock(data_mutex_);
1350  void * buf = (char *)buffers_ + buffer * data_size;
1351  interface_data_ts_t *buf_ts = (interface_data_ts_t *)buf;
1352  return Time(buf_ts->timestamp_sec, buf_ts->timestamp_usec);
1353 }
1354 
1355 /** Get time of a buffer.
1356  * Use this method to query the time without allocating a new Time instance.
1357  * @param buffer buffer number
1358  * @param timestamp upon return contains the timestamp of the buffer.
1359  */
1360 void
1361 Interface::buffer_timestamp(unsigned int buffer, Time *timestamp)
1362 {
1363  if (buffer >= num_buffers_) {
1364  throw OutOfBoundsException("Buffer ID out of bounds", buffer, 0, num_buffers_);
1365  }
1366  if (timestamp == NULL) {
1367  throw NullPointerException("%s.buffer_timestamp: timestamp cannot be null", uid_);
1368  }
1369 
1370  MutexLocker lock(data_mutex_);
1371  void * buf = (char *)buffers_ + buffer * data_size;
1372  interface_data_ts_t *buf_ts = (interface_data_ts_t *)buf;
1373  timestamp->set_time(buf_ts->timestamp_sec, buf_ts->timestamp_usec);
1374 }
1375 
1376 /** Parse UID to type and ID strings.
1377  * Note that the returned values (type and id) must be freed once they are
1378  * no longer used. Also verifies lengths of the type and id strings.
1379  * @param uid UID to parse
1380  * @param type upon return contains the type part of the UID
1381  * @param id upon return contains the ID part
1382  */
1383 void
1384 Interface::parse_uid(const char *uid, std::string &type, std::string &id)
1385 {
1386  regex_t re;
1387  int ec = 0;
1388 // Requires in parse_uid()
1389 #define str(s) #s
1390 #define xstr(s) str(s)
1391  if ((ec = regcomp(&re,
1392  "^([a-zA-Z0-9]{1," xstr(INTERFACE_TYPE_SIZE_) "})::"
1393  "([a-zA-Z0-9 _/\\.-]{1," xstr(
1394  INTERFACE_ID_SIZE_) "})$",
1395  REG_EXTENDED))
1396  != 0) {
1397  char errbuf[1024];
1398  regerror(ec, &re, errbuf, 1024);
1399  throw Exception("Failed to created regular expression to parse UID (%s)", errbuf);
1400  }
1401  regmatch_t matches[3];
1402  if (regexec(&re, uid, 3, matches, 0) != 0) {
1403  regfree(&re);
1404  throw Exception("Failed to match UID %s, format error.", uid);
1405  }
1406 
1407  type.assign(&(uid[matches[1].rm_so]), matches[1].rm_eo - matches[1].rm_so);
1408  id.assign(&(uid[matches[2].rm_so]), matches[2].rm_eo - matches[2].rm_so);
1409 
1410  regfree(&re);
1411 }
1412 
1413 } // end namespace fawkes
void copy_private_to_buffer(unsigned int buffer)
Copy data from private memory to buffer.
Definition: interface.cpp:1286
Interface field iterator.
virtual bool exists_writer(const Interface *interface) const =0
Check if a writer exists for the given interface.
This exception is thrown if an interface is invalid and it is attempted to call read()/write().
Definition: interface.h:72
int64_t timestamp_sec
time in seconds since Unix epoch
Definition: interface.h:199
const char * owner() const
Get owner of interface.
Definition: interface.cpp:660
bool operator==(Interface &comp) const
Check equality of two interfaces.
Definition: interface.cpp:620
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:852
MessageQueue::MessageIterator msgq_begin()
Get start iterator for message queue.
Definition: interface.cpp:1123
unsigned int datasize() const
Get data size.
Definition: interface.cpp:528
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:41
unsigned int id() const
Get message ID.
Definition: message.cpp:190
static Clock * instance()
Clock initializer.
Definition: clock.cpp:63
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:1026
InterfaceInvalidMessageException(const Interface *interface, const Message *message)
Constructor.
Definition: interface.cpp:92
void unref()
Decrement reference count and conditionally delete this instance.
Definition: refcount.cpp:95
void get_timestamp(long &sec, long &usec) const
Get time stamp.
Definition: time.h:137
void lock_for_read()
Aquire a reader lock.
void set_hash(unsigned char *ihash)
Set hash.
Definition: interface.cpp:316
Interface field info list.
Definition: types.h:57
unsigned int msgq_enqueue_copy(Message *message)
Enqueue copy of message at end of queue.
Definition: interface.cpp:917
void set_auto_timestamping(bool enabled)
Enable or disable automated timestamping.
Definition: interface.cpp:743
MessageIterator end()
Get iterator to element beyond end of message queue list.
Fawkes library namespace.
void msgq_unlock()
Unlock message queue.
Definition: interface.cpp:1101
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
const char * name
Name of this field.
Definition: types.h:61
interface_messageinfo_t * next
the next field, NULL if last
Definition: interface.h:192
Mutex locking helper.
Definition: mutex_locker.h:33
unsigned int data_size
Minimal data size to hold data storage.
Definition: interface.h:225
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:974
const char * id() const
Get identifier of interface.
Definition: interface.cpp:649
interface_fieldinfo_t * next
next field, NULL if last
Definition: types.h:65
A class for handling time.
Definition: time.h:92
A NULL pointer was supplied where not allowed.
Definition: software.h:31
virtual unsigned int num_readers(const Interface *interface) const =0
Get number of readers.
InterfaceMessageEnqueueException(const char *type, const char *id)
Constructor.
Definition: interface.cpp:74
void write()
Write from local copy into BlackBoard memory.
Definition: interface.cpp:494
void msgq_append(Message *message)
Enqueue message.
Definition: interface.cpp:950
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:78
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:1083
virtual std::string writer(const Interface *interface) const =0
Get writer of interface.
bool is_valid() const
Check validity of interface.
Definition: interface.cpp:462
unsigned int msgq_size()
Get size of message queue.
Definition: interface.cpp:1009
Interface()
Constructor.
Definition: interface.cpp:233
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
void * value
Current value of this field.
Definition: types.h:63
Time buffer_timestamp(unsigned int buffer)
Get time of a buffer.
Definition: interface.cpp:1343
unsigned int num_fields()
Get the number of fields in the interface.
Definition: interface.cpp:1213
unsigned int mem_serial() const
Get memory serial of interface.
Definition: interface.cpp:692
const unsigned char * hash() const
Get interface hash.
Definition: interface.cpp:298
const interface_enum_map_t * enum_map
Map of possible enum values.
Definition: types.h:64
void lock_for_write()
Aquire a writer lock.
void add_messageinfo(const char *name)
Add an entry to the message info list.
Definition: interface.cpp:375
void msgq_pop()
Erase first message from queue.
Definition: interface.cpp:1179
bool data_changed
Indicator if data has changed.
Definition: interface.h:226
const char * type() const
Get type of interface.
Definition: interface.cpp:640
void * data_ptr
Pointer to local memory storage.
Definition: interface.h:224
void read_from_buffer(unsigned int buffer)
Copy data from buffer to private memory.
Definition: interface.cpp:1302
Base class for exceptions in Fawkes.
Definition: exception.h:35
Message * msgq_first()
Get the first message from the message queue.
Definition: interface.cpp:1164
InterfaceWriteDeniedException(const char *type, const char *id, const char *msg)
Constructor.
Definition: interface.cpp:54
void set_clock(Clock *clock)
Set clock for this instance.
Definition: time.cpp:308
virtual bool message_valid(const Message *message) const =0
Check if the message is valid and can be enqueued.
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:683
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
void flush()
Delete all messages from queue.
virtual ~Interface()
Destructor.
Definition: interface.cpp:262
int64_t timestamp_usec
additional time microseconds
Definition: interface.h:200
void ref()
Increment reference count.
Definition: refcount.cpp:67
Message queue used in interfaces.
Definition: message_queue.h:41
InterfaceInvalidException(const Interface *interface, const char *method)
Constructor.
Definition: interface.cpp:110
interface_fieldtype_t type
type of this field
Definition: types.h:59
bool has_writer() const
Check if there is a writer for the interface.
Definition: interface.cpp:814
Timestamp data, must be present and first entries for each interface data structs!...
Definition: interface.h:197
void copy_shared_to_buffer(unsigned int buffer)
Copy data from private memory to buffer.
Definition: interface.cpp:1260
unsigned int size() const
Get number of messages in queue.
const char * uid() const
Get unique identifier of interface.
Definition: interface.cpp:674
bool oftype(const char *interface_type) const
Check if interface is of given type.
Definition: interface.cpp:631
size_t hash_size() const
Get size of interface hash.
Definition: interface.cpp:419
bool try_lock()
Try to lock message queue.
size_t length
Length of field (array, string)
Definition: types.h:62
virtual void notify_of_data_change(const Interface *interface)=0
Notify of data change.
const Time * timestamp() const
Get timestamp of last write.
Definition: interface.cpp:702
bool is_writer() const
Check if this is a writing instance.
Definition: interface.cpp:438
bool changed() const
Check if data has been changed.
Definition: interface.cpp:777
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:879
MessageIterator begin()
Get iterator to first element in message queue.
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: interface.cpp:1204
void set_time(const timeval *tv)
Sets the time.
Definition: time.cpp:246
void set_clock(Clock *clock)
Set clock to use for timestamping.
Definition: interface.cpp:733
void resize_buffers(unsigned int num_buffers)
Resize buffer array.
Definition: interface.cpp:1225
const char * enumtype
text representation of enum type
Definition: types.h:60
static void parse_uid(const char *uid, std::string &type, std::string &id)
Parse UID to type and ID strings.
Definition: interface.cpp:1384
void msgq_flush()
Flush all messages.
Definition: interface.cpp:1043
void append(Message *msg)
Append message to queue.
void msgq_lock()
Lock message queue.
Definition: interface.cpp:1062
virtual std::list< std::string > readers(const Interface *interface) const =0
Get owners of interfaces who opened for reading.
int compare_buffers(unsigned int buffer)
Compare buffer to private memory.
Definition: interface.cpp:1324
unsigned int num_buffers() const
Get number of buffers.
Definition: interface.cpp:1251
void set_validity(bool valid)
Mark this interface invalid.
Definition: interface.cpp:451
virtual void transmit(Message *message)=0
Transmit message.
bool empty() const
Check if message queue is empty.
void lock()
Lock this mutex.
Definition: mutex.cpp:87
Time & stamp()
Set this time to the current time.
Definition: time.cpp:704
void remove(const Message *msg)
Remove message from queue.
const void * datachunk() const
Get data chunk.
Definition: interface.cpp:429
void unlock()
Release the lock.
void pop()
Erase first message from queue.
unsigned int num_readers() const
Get the number of readers.
Definition: interface.cpp:842
void unlock()
Unlock message queue.
interface_data_ts_t * data_ts
Pointer to data casted to timestamp struct.
Definition: interface.h:228
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: interface.cpp:1195
Message * first()
Get first message from queue.
Mutex mutual exclusion lock.
Definition: mutex.h:32
Index out of bounds.
Definition: software.h:85
void set_from_chunk(void *chunk)
Set from a raw data chunk.
Definition: interface.cpp:797
void lock()
Lock message queue.
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:36
std::list< std::string > readers() const
Get owner names of reading interface instances.
Definition: interface.cpp:861
std::map< int, std::string > interface_enum_map_t
Map of enum integer to string values.
Definition: types.h:54
void set_timestamp(const Time *t=NULL)
Set timestamp.
Definition: interface.cpp:712
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
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:208
virtual Message * clone() const
Clone this message.
Definition: message.cpp:393
void mark_data_changed()
Mark data as changed.
Definition: interface.cpp:755
const char * hash_printable() const
Get printable interface hash.
Definition: interface.cpp:307
MessageQueue::MessageIterator msgq_end()
Get end iterator for message queue.
Definition: interface.cpp:1145