Fawkes API  Fawkes Development Version
interface.cpp
00001 
00002 /***************************************************************************
00003  *  interface.cpp - BlackBoard Interface
00004  *
00005  *  Created: Mon Oct 09 18:54:50 2006
00006  *  Copyright  2006-2009  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <interface/interface.h>
00025 
00026 #include <interface/mediators/interface_mediator.h>
00027 #include <interface/mediators/message_mediator.h>
00028 #include <core/threading/refc_rwlock.h>
00029 #include <core/threading/mutex.h>
00030 #include <core/exceptions/system.h>
00031 #include <utils/time/clock.h>
00032 #include <utils/time/time.h>
00033 #include <utils/misc/strndup.h>
00034 
00035 #include <cstring>
00036 #include <cstdio>
00037 #include <cstdlib>
00038 #include <cerrno>
00039 #include <typeinfo>
00040 #include <regex.h>
00041 
00042 namespace fawkes {
00043 
00044 /** @class InterfaceWriteDeniedException <interface/interface.h>
00045  * This exception is thrown if a write has been attempted on a read-only interface.
00046  * @see Interface::write()
00047  * @ingroup Exceptions
00048  */
00049 
00050 /** Constructor.
00051  * @param type type of the interface which caused the exception
00052  * @param id id of the interface which caused the exception
00053  * @param msg additional informative message
00054  */
00055 InterfaceWriteDeniedException::InterfaceWriteDeniedException(const char *type,
00056                                                              const char *id,
00057                                                              const char *msg)
00058   : Exception("This interface instance '%s' of type '%s' is not opened for writing. %s",
00059               id, type, msg)
00060 {
00061 }
00062 
00063 /** @class InterfaceMessageEnqueueException <interface/interface.h>
00064  * This exception is thrown if a write has been attempted on a read-only interface.
00065  * @see Interface::write()
00066  * @ingroup Exceptions
00067  */
00068 
00069 /** Constructor.
00070  * @param type type of the interface which caused the exception
00071  * @param id id of the interface which caused the exception
00072  */
00073 InterfaceMessageEnqueueException::InterfaceMessageEnqueueException(const char *type,
00074                                                                    const char *id)
00075   : Exception("This interface instance '%s' of type '%s' IS opened for writing, but "
00076               "messages can only be enqueued on reading interfaces.", id, type)
00077 {
00078 }
00079 
00080 /** @class InterfaceInvalidMessageException <interface/interface.h>
00081  * This exception is thrown if a message has been queued in the interface which is
00082  * not recognized by the interface.
00083  * @ingroup Exceptions
00084  */
00085 
00086 /** Constructor.
00087  * @param interface interface that the invalid message was enqueued to
00088  * @param message enqueued message
00089  */
00090 InterfaceInvalidMessageException::InterfaceInvalidMessageException(const Interface *interface,
00091                                                                    const Message *message)
00092   : Exception("Message of type '%s' cannot be enqueued in interface of type '%s'",
00093               message->type(), interface->type())
00094 {
00095 }
00096 
00097 
00098 /** @class InterfaceInvalidException <interface/interface.h>
00099  * This exception is thrown if an interface is invalid and it is attempted to call
00100  * read()/write().
00101  * @ingroup Exceptions
00102  */
00103 
00104 /** Constructor.
00105  * @param interface invalid interface that the operation was tried on
00106  * @param method the method that was tried to execute
00107  */
00108 InterfaceInvalidException::InterfaceInvalidException(const Interface *interface,
00109                                                      const char *method)
00110   : Exception("The interface %s (instance serial %u) is invalid. You cannot call %s anymore.",
00111               interface->uid(), interface->serial(), method)
00112 {
00113 }
00114 
00115 
00116 /** @class Interface <interface/interface.h>
00117  * Base class for all Fawkes BlackBoard interfaces.
00118  *
00119  * Interfaces are identified by a type and an ID. The type is just a
00120  * textual representation of the class name. The ID identifies a
00121  * specific instance of this interface type. Additionally each
00122  * interface has a hash. The hash is an MD5 digest of the XML config
00123  * file that was fed to the interface generator to create the
00124  * interface. It is used to detect incompatible versions of the same
00125  * interface type.
00126  *
00127  * Interfaces have at least two sections of memory which contains a
00128  * struct composed of the internal data of the interface. The first is
00129  * shared with either the LocalBlackBoard instance (and hence all
00130  * other instances of the interface) or with a transmission thread of
00131  * a RemoteBlackBoard. The second is a private copy of the data. The
00132  * data is copied between the shared and private section only upon
00133  * request. Interfaces are either reading or writing, denoting their
00134  * kind of access towards the shared memory section. At any point in
00135  * time there may at most exist one writer for an interface, but any
00136  * number of readers. The shared section is protected by a
00137  * ReadWriteLock. For a writer, a call to write() will copy the data
00138  * from the private to the shared section. For a reader, a call to
00139  * read() will copy the data from the shared to the private
00140  * section. Upon opening the interface, the private section is copied
00141  * once from the shared section, even when opening a writer.
00142  *
00143  * An interface has an internal timestamp. This timestamp indicates
00144  * when the data in the interface has been modified last. The
00145  * timestamp is usually automatically updated. But it some occasions
00146  * the writer may choose to provide its own timestamp data. This can
00147  * be useful for example for an interface providing hardware data to
00148  * give the exact capture time.  In the automatic case nothing has to
00149  * be done manually. The timestamp is updated automatically by calling
00150  * the write() method if and only if the data in the interface has
00151  * actually been modified. The reader can call changed() to see if the
00152  * data changed.  In the non-automatic case the writer must first
00153  * disable automatic timestamping using set_auto_timestamping(). Then
00154  * it must provide a timestamp everytime before calling write(). Note
00155  * that setting the timestamp already marks the interface as having
00156  * changed. So set the timestamp only if the data has changed and the
00157  * readers should see this.
00158  *
00159  * An interface provides support for buffers. Like the shared and
00160  * private memory sections described above, buffers are additional
00161  * memory sections that can be used to save data from the shared
00162  * section or save or restore from and to the private memory
00163  * section. One example use case is to save the current shared memory
00164  * content at one point in time at a specific main loop hook, and
00165  * restore it only later at a suitable time in another continuous
00166  * thread. Another useful application is to keep a history for
00167  * hysteresis processing, or to observe the development of the values
00168  * in an interface.
00169  *
00170  * Interfaces are not created directly, but rather by using the
00171  * interface generator.
00172  *
00173  * @author Tim Niemueller
00174  */
00175 
00176 /** @var Interface::data_ptr
00177  * Pointer to local memory storage
00178  */
00179 
00180 /** @var Interface::data_ts
00181  * Pointer to data casted to timestamp struct. This assumes that the very
00182  * first two entries are 64 bit wide signed integers containing seconds and
00183  * microseconds since the Unix epoch.
00184  */
00185 
00186 /** @var Interface::data_size
00187  * Minimal data size to hold data storage.
00188  */
00189 
00190 /** @var Interface::data_changed
00191  * Indicator if data has changed.
00192  * This must be set by all methods that manipulate internal data or the
00193  * timestamp. Only if set to true a call to write() will update data_ts.
00194  */
00195 
00196 /** @fn bool Interface::message_valid(const Message *message) const = 0
00197  * Check if the message is valid and can be enqueued.
00198  * @param message The message to check
00199  * @return true, if the message is valid and may be enqueued, false otherwise
00200  *
00201  * @fn bool Interface::create_message(const char *type) const = 0
00202  * Create message based on type name.
00203  * This will create a new message of the given type. The type must be
00204  * given without the InterfaceName:: prefix but just the plain class
00205  * name of the message.
00206  * @param type message type
00207  * @return message of the given type, empty
00208  * @exception UnknownTypeException thrown if this interface cannot
00209  * create a message of the given type.
00210  *
00211  * @fn void Interface::copy_values(const Interface *interface) = 0
00212  * Copy values from another interface.
00213  * The operation will only succeed if the supplied interface is of the same
00214  * type as this instance.
00215  * @param interface interface to copy from
00216  *
00217  * @fn const char * Interface::enum_tostring(const char *enumtype, int val) const
00218  * Convert arbitrary enum value to string.
00219  * Given the string representation of the enum type and the value this method
00220  * returns the string representation of the specific value, or the string
00221  * UNKNOWN if the value is not defined. An exception is thrown if the enum
00222  * type is invalid.
00223  * @param enumtype enum type as string
00224  * @param val value to convert
00225  * @return string representation of value
00226  * @exception UnknownTypeException thrown if enumtype is not specified for
00227  * interface.
00228  */
00229 
00230 /** Constructor */
00231 Interface::Interface()
00232 {
00233   __write_access = false;
00234   __rwlock = NULL;
00235   __valid = true;
00236   __next_message_id = 0;
00237   __num_fields = 0;
00238   __fieldinfo_list   = NULL;
00239   __messageinfo_list = NULL;
00240   __clock = Clock::instance();
00241   __timestamp = new Time(0, 0);
00242   __local_read_timestamp = new Time(0, 0);
00243   __auto_timestamping = true;
00244   data_changed = false;
00245   memset(__hash, 0, __INTERFACE_HASH_SIZE);
00246   memset(__hash_printable, 0, __INTERFACE_HASH_SIZE * 2 + 1);
00247 
00248   data_ptr  = NULL;
00249   data_size = 0;
00250 
00251   __buffers = NULL;
00252   __num_buffers = 0;
00253 
00254   __message_queue = new MessageQueue();
00255   __data_mutex = new Mutex();
00256 }
00257 
00258 
00259 /** Destructor */
00260 Interface::~Interface()
00261 {
00262   if ( __rwlock) __rwlock->unref();
00263   delete __data_mutex;
00264   delete __message_queue;
00265   if (__buffers)  free(__buffers);
00266   // free fieldinfo list
00267   interface_fieldinfo_t *finfol = __fieldinfo_list;
00268   while ( finfol ) {
00269     __fieldinfo_list = __fieldinfo_list->next;
00270     free(finfol);
00271     finfol = __fieldinfo_list;
00272   }
00273   // free messageinfo list
00274   interface_messageinfo_t *minfol = __messageinfo_list;
00275   while ( minfol ) {
00276     __messageinfo_list = __messageinfo_list->next;
00277     free(minfol);
00278     minfol = __messageinfo_list;
00279   }
00280   delete __timestamp;
00281   delete __local_read_timestamp;
00282 }
00283 
00284 /** Get interface hash.
00285  * The interface is a unique version identifier of an interface. It is
00286  * the has of the input XML file during the generation of the
00287  * interface. It is meant to be used to ensure that all sides are
00288  * using the exact same version of an interface.
00289  * @return constant byte string containing the hash value of hash_size() length
00290  */
00291 const unsigned char *
00292 Interface::hash() const
00293 {
00294   return __hash;
00295 }
00296 
00297 
00298 /** Get printable interface hash.
00299  * @return printable version of hash()
00300  */
00301 const char *
00302 Interface::hash_printable() const
00303 {
00304   return __hash_printable;
00305 }
00306 
00307 
00308 /** Set hash. Never use directly.
00309  * @param ihash interface hash
00310  */
00311 void
00312 Interface::set_hash(unsigned char *ihash)
00313 {
00314   memcpy(__hash, ihash, __INTERFACE_HASH_SIZE);
00315   for (size_t s = 0; s < __INTERFACE_HASH_SIZE; ++s) {
00316     snprintf(&__hash_printable[s*2], 3, "%02X", __hash[s]);
00317   }
00318 }
00319 
00320 
00321 /** Add an entry to the field info list.
00322  * Never use directly, use the interface generator instead. The info list
00323  * is used for introspection purposes to allow for iterating over all fields
00324  * of an interface.
00325  * @param type field type
00326  * @param name name of the field, this is referenced, not copied
00327  * @param length length of the field
00328  * @param value pointer to the value in the data struct
00329  * @param enumtype name of the enum type, valid only if type == IFT_ENUM.
00330  */
00331 void
00332 Interface::add_fieldinfo(interface_fieldtype_t type, const char *name,
00333                          size_t length, void *value, const char *enumtype)
00334 {
00335   interface_fieldinfo_t *infol = __fieldinfo_list;
00336   interface_fieldinfo_t *newinfo =
00337     (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
00338 
00339   newinfo->type     = type;
00340   newinfo->enumtype = enumtype;
00341   newinfo->name     = name;
00342   newinfo->length   = length;
00343   newinfo->value    = value;
00344   newinfo->next     = NULL;
00345 
00346   if ( infol == NULL ) {
00347     // first entry
00348     __fieldinfo_list = newinfo;
00349   } else {
00350     // append to list
00351     while ( infol->next != NULL ) {
00352       infol = infol->next;
00353     }
00354     infol->next = newinfo;
00355   }
00356 
00357   ++__num_fields;
00358 }
00359 
00360 
00361 /** Add an entry to the message info list.
00362  * Never use directly, use the interface generator instead. The info list
00363  * is used for introspection purposes to allow for iterating over all message
00364  * types of an interface.
00365  * @param type the type of the message
00366  */
00367 void
00368 Interface::add_messageinfo(const char *type)
00369 {
00370   interface_messageinfo_t *infol = __messageinfo_list;
00371   interface_messageinfo_t *newinfo =
00372     (interface_messageinfo_t *)malloc(sizeof(interface_messageinfo_t));
00373 
00374   newinfo->type = type;
00375   newinfo->next = NULL;
00376 
00377   if ( infol == NULL ) {
00378     // first entry
00379     __messageinfo_list = newinfo;
00380   } else {
00381     // append to list
00382     while ( infol->next != NULL ) {
00383       infol = infol->next;
00384     }
00385     infol->next = newinfo;
00386   }
00387 }
00388 
00389 
00390 /** Obtain a list of textual representations of the message types
00391  * available for this interface.
00392  * @return the message types
00393  */
00394 std::list<const char *>
00395 Interface::get_message_types()
00396 {
00397   std::list<const char *> types;
00398   interface_messageinfo_t *cur = __messageinfo_list;
00399 
00400   while ( cur != NULL ) {
00401     types.push_back(cur->type);
00402     cur = cur->next;
00403   }
00404 
00405   return types;
00406 }
00407 
00408 
00409 /** Get size of interface hash.
00410  * Returns the size in bytes of the interface hash. This depends on the used hash.
00411  * @return size of interface hash string
00412  */
00413 size_t
00414 Interface::hash_size() const
00415 {
00416   return __INTERFACE_HASH_SIZE;
00417 }
00418 
00419 
00420 /** Get data chunk.
00421  * Use sparsely
00422  * @return const pointer to the data chunk
00423  */
00424 const void *
00425 Interface::datachunk() const
00426 {
00427   return data_ptr;
00428 }
00429 
00430 
00431 /** Check if this is a writing instance.
00432  * @return true if this is a writing instance, false otherwise
00433  */
00434 bool
00435 Interface::is_writer() const
00436 {
00437   return __write_access;
00438 }
00439 
00440 
00441 /** Mark this interface invalid.
00442  * An interface can become invalid, for example if the connection of a
00443  * RemoteBlackBoard dies. In this case the interface becomes invalid
00444  * and successive read()/write() calls will throw an
00445  * InterfaceInvalidException.
00446  * @param valid true to mark the interface valid or false to mark it invalid
00447  */
00448 void
00449 Interface::set_validity(bool valid)
00450 {
00451   __rwlock->lock_for_write();
00452   __valid = valid;
00453   __rwlock->unlock();
00454 }
00455 
00456 
00457 /** Check validity of interface.
00458  * @return true if interface is valid, false otherwise
00459  */
00460 bool
00461 Interface::is_valid() const
00462 {
00463   return __valid;
00464 }
00465 
00466 
00467 /** Read from BlackBoard into local copy.
00468  * @exception InterfaceInvalidException thrown if the interface has
00469  * been marked invalid
00470  */
00471 void
00472 Interface::read()
00473 {
00474   __rwlock->lock_for_read();
00475   __data_mutex->lock();
00476   if ( __valid ) {
00477     memcpy(data_ptr, __mem_data_ptr, data_size);
00478     *__local_read_timestamp = *__timestamp;
00479     __timestamp->set_time(data_ts->timestamp_sec, data_ts->timestamp_usec);
00480   } else {
00481     __data_mutex->unlock();
00482     __rwlock->unlock();
00483     throw InterfaceInvalidException(this, "read()");
00484   }
00485   __data_mutex->unlock();
00486   __rwlock->unlock();
00487 }
00488 
00489 
00490 /** Write from local copy into BlackBoard memory.
00491  * @exception InterfaceInvalidException thrown if the interface has
00492  * been marked invalid
00493  */
00494 void
00495 Interface::write()
00496 {
00497   if ( ! __write_access ) {
00498     throw InterfaceWriteDeniedException(__type, __id, "Cannot write.");
00499   }
00500 
00501   __rwlock->lock_for_write();
00502   __data_mutex->lock();
00503   if ( __valid ) {
00504     if (data_changed) {
00505       if (__auto_timestamping)  __timestamp->stamp();
00506       long sec = 0, usec = 0;
00507       __timestamp->get_timestamp(sec, usec);
00508       data_ts->timestamp_sec  = sec;
00509       data_ts->timestamp_usec = usec;
00510       data_changed = false;
00511     }
00512     memcpy(__mem_data_ptr, data_ptr, data_size);
00513   } else {
00514     __data_mutex->unlock();
00515     __rwlock->unlock();
00516     throw InterfaceInvalidException(this, "write()");
00517   }
00518   __data_mutex->unlock();
00519   __rwlock->unlock();
00520 
00521   __interface_mediator->notify_of_data_change(this);
00522 }
00523 
00524 
00525 /** Get data size.
00526  * @return size in bytes of data segment
00527  */
00528 unsigned int
00529 Interface::datasize() const
00530 {
00531   return data_size;
00532 }
00533 
00534 
00535 /** Set type, ID and UID.
00536  * Sets type and ID, UID is generated automatically as Type::ID.
00537  * @param type string, a maxmimum of __INTERFACE_TYPE_SIZE bytes are copied
00538  * @param ID string, a maxmimum of __INTERFACE_ID_SIZE bytes are copied
00539  */
00540 void
00541 Interface::set_type_id(const char *type, const char *id)
00542 {
00543   __type[__INTERFACE_TYPE_SIZE] = 0;
00544   __id[__INTERFACE_ID_SIZE] = 0;
00545   __uid[__INTERFACE_UID_SIZE] = 0;
00546   strncpy(__type, type, __INTERFACE_TYPE_SIZE);
00547   strncpy(__id, id, __INTERFACE_ID_SIZE);
00548   snprintf(__uid, __INTERFACE_UID_SIZE, "%s::%s", type, id);
00549 }
00550 
00551 
00552 /** Set instance serial.
00553  * @param instance_serial instance serial
00554  */
00555 void
00556 Interface::set_instance_serial(unsigned short instance_serial)
00557 {
00558   __instance_serial = instance_serial;
00559 }
00560 
00561 
00562 /** Set mediators.
00563  * @param iface_mediator interface mediator
00564  * @param msg_mediator message mediator.
00565  */
00566 void
00567 Interface::set_mediators(InterfaceMediator *iface_mediator,
00568                          MessageMediator *msg_mediator)
00569 {
00570   __interface_mediator = iface_mediator;
00571   __message_mediator   = msg_mediator;
00572 }
00573 
00574 
00575 /** Set memory data.
00576  * @param serial mem serial
00577  * @param real_ptr pointer to whole chunk
00578  * @param data_ptr pointer to data chunk
00579  */
00580 void
00581 Interface::set_memory(unsigned int serial, void *real_ptr, void *data_ptr)
00582 {
00583   __mem_serial   = serial;
00584   __mem_real_ptr = real_ptr;
00585   __mem_data_ptr = data_ptr;
00586 }
00587 
00588 
00589 /** Set read/write info.
00590  * @param write_access true to enable write access, false for read-only
00591  * @param rwlock read/write lock for this interface
00592  */
00593 void
00594 Interface::set_readwrite(bool write_access, RefCountRWLock *rwlock)
00595 {
00596   __write_access = write_access;
00597   __rwlock       = rwlock;
00598 }
00599 
00600 
00601 /** Check equality of two interfaces.
00602  * Two interfaces are the same if their types and identifiers are
00603  * equal.  This does not mean that both interfaces are the very same
00604  * instance for accessing the BlackBoard. Instead this just means that
00605  * both instances will access the same chunk of memory in the
00606  * BlackBoard and the instances MAY be the same.  If you want to know
00607  * if two instances are exactly the same compare the instance serials
00608  * using the serial() method.
00609  * @param comp interface to compare current instance with
00610  * @return true, if interfaces point to the same data, false otherwise
00611  */
00612 bool
00613 Interface::operator==(Interface &comp) const
00614 {
00615   return ( (strncmp(__type, comp.__type, sizeof(__type)) == 0) &&
00616            (strncmp(__id, comp.__id, sizeof(__id)) == 0) );
00617 }
00618 
00619 
00620 /** Check if interface is of given type.
00621  * @param interface_type type to query
00622  * @return true, if current instance is of given type, false otherwise
00623  */
00624 bool
00625 Interface::oftype(const char *interface_type) const
00626 {
00627   return (strncmp(this->__type, interface_type, sizeof(this->__type)) == 0);
00628 }
00629 
00630 
00631 /** Get type of interface.
00632  * @return string with the type of the interface.
00633  */
00634 const char *
00635 Interface::type() const
00636 {
00637   return __type;
00638 }
00639 
00640 
00641 /** Get identifier of interface.
00642  * @return string with the identifier of the interface.
00643  */
00644 const char *
00645 Interface::id() const
00646 {
00647   return __id;
00648 }
00649 
00650 
00651 /** Get unique identifier of interface.
00652  * As the name suggests this ID denotes a unique memory instance of
00653  * this interface in the blackboard. It is provided by the system and
00654  * currently returns a string of the form "type::id", where type is
00655  * replaced by the type returned by type() and id is the ID returned
00656  * by id().
00657  * @return string with the unique identifier of the interface.
00658  */
00659 const char *
00660 Interface::uid() const
00661 {
00662   return __uid;
00663 }
00664 
00665 
00666 /** Get instance serial of interface.
00667  * @return instance serial of the interface.
00668  */
00669 unsigned short
00670 Interface::serial() const
00671 {
00672   return __instance_serial;
00673 }
00674 
00675 
00676 /** Get memory serial of interface.
00677  * @return memory serial of interface
00678  */
00679 unsigned int
00680 Interface::mem_serial() const
00681 {
00682   return __mem_serial;
00683 }
00684 
00685 
00686 /** Get timestamp of last write.
00687  * Note that you need to call read() before this provides useful information.
00688  * @return timestamp of last write.
00689  */
00690 const Time *
00691 Interface::timestamp() const
00692 {
00693   return __timestamp;
00694 }
00695 
00696 
00697 /** Set timestamp.
00698  * @param t time stamp to copy time from, if NULL current time is queried
00699  * from clock.
00700  */
00701 void
00702 Interface::set_timestamp(const Time *t)
00703 {
00704   if (__auto_timestamping) throw Exception("Auto timestamping enabled, cannot "
00705                                             "set explicit timestamp");
00706   if (!__write_access) throw Exception("Timestamp can only be set on writing "
00707                                        "instance");
00708 
00709   if (t) {
00710     *__timestamp = t;
00711   } else {
00712     __timestamp->stamp();
00713   }
00714   data_changed = true;
00715 }
00716 
00717 
00718 /** Set clock to use for timestamping.
00719  * @param clock clock to use from now on
00720  */
00721 void
00722 Interface::set_clock(Clock *clock)
00723 {
00724   __clock = clock;
00725   __timestamp->set_clock(clock);
00726 }
00727 
00728 
00729 /** Enable or disable automated timestamping.
00730  * @param enabled true to enable automated timestamping, false to disable
00731  */
00732 void
00733 Interface::set_auto_timestamping(bool enabled)
00734 {
00735   __auto_timestamping = enabled;
00736 }
00737 
00738 
00739 /** Check if data has been changed.
00740  * Note that if the data has been modified this method will return
00741  * true at least until the next call to read. From then on it will
00742  * return false if the data has not been modified between the two
00743  * read() calls and still true otherwise.
00744  * @return true if data has been changed between the last call to
00745  * read() and the one before.
00746  */
00747 bool
00748 Interface::changed() const
00749 {
00750   return (*__timestamp != __local_read_timestamp);
00751 }
00752 
00753 
00754 /** Set from a raw data chunk.
00755  * This allows for setting the interface data from a raw chunk. This
00756  * is not useful in general but only in rare situations like network
00757  * transmission. Do not use it unless you really know what you are
00758  * doing. The method expects the chunk to be exactly of the size
00759  * returned by datasize(). No check is done, a segfault will most
00760  * likely occur if you provide invalid data.
00761  * @param chunk data chunk, must be exactly of the size that is
00762  * returned by datasize()
00763  */
00764 void
00765 Interface::set_from_chunk(void *chunk)
00766 {
00767   // This could be checked but should never happen with our generated
00768   // interfaces anyway
00769   // if ( data_ptr == NULL )
00770   //   throw NullPointerException("Interface not initialized");
00771 
00772   memcpy(data_ptr, chunk, data_size);
00773 }
00774 
00775 /** Check if there is a writer for the interface.
00776  * Use this method to determine if there is any open instance of the
00777  * interface that is writing to the interface. This can also be the
00778  * queried interface instance.
00779  * @return true if a writer for the interface exists, false otherwise
00780  */
00781 bool
00782 Interface::has_writer() const
00783 {
00784   return __interface_mediator->exists_writer(this);
00785 }
00786 
00787 
00788 /** Get the number of readers.
00789  * Use this method to determine how many reading instances of the
00790  * interface currently exist. If the current instance is a reading
00791  * instance it will be included in the count number. To determine if
00792  * you are the last man having this interface you can use the
00793  * following code:
00794  * @code
00795  * // for a writing instance:
00796  * if ( interface->num_readers == 0 ) {
00797  *   // we are the last one to have this interface open
00798  * }
00799  *
00800  * // for a reading instance:
00801  * if ( ! interface->has_writer() && (interface->num_readers() == 0) ) {
00802  *   // we are the last one to have this interface open
00803  * }
00804  * @endcode
00805  * Note that this can result in a race condition. You have to be
00806  * registered as a BlackBoardEventListener to be sure that you are
00807  * really the last.
00808  * @return number of readers
00809  */
00810 unsigned int
00811 Interface::num_readers() const
00812 {
00813   return __interface_mediator->num_readers(this);
00814 }
00815 
00816 
00817 /** Enqueue message at end of queue.
00818  * This appends the given message to the queue and transmits the
00819  * message via the message mediator. The message is afterwards owned
00820  * by the other side and will be unrefed and freed as soon as it has
00821  * been processed. If you want to keep this message to read a feedback
00822  * status you have to reference it _before_ enqueuing it!
00823  * This can only be called on a reading interface instance.
00824  * @param message Message to enqueue.
00825  * @return message id after message has been queued
00826  * @exception MessageAlreadyQueuedException thrown if the message has
00827  * already been enqueued to an interface.
00828  */
00829 unsigned int
00830 Interface::msgq_enqueue(Message *message)
00831 {
00832   if ( __write_access ) {
00833     throw InterfaceMessageEnqueueException(__type, __id);
00834   }
00835   
00836   if ( message_valid(message) ) {
00837     message->set_interface(this);
00838     message->set_id(next_msg_id());
00839     // transmit might change the message id!
00840     __message_mediator->transmit(message);
00841     unsigned int msgid = message->id();
00842     message->unref();
00843     return msgid;
00844   } else {
00845     throw InterfaceInvalidMessageException(this, message);
00846   }
00847 }
00848 
00849 
00850 /** Enqueue copy of message at end of queue.
00851 
00852  * This method creates a copy of the message and enqueues it. Note
00853  * that this way you cannot receive status message in the message,
00854  * because the other side will not use your message instance but a
00855  * copy instead.
00856  *
00857  * This is particularly useful if you call from an environment with
00858  * automatic garbage collection that does not honor the referencing
00859  * feature of message but rather just deletes it.
00860  *
00861  * This can only be called on a reading interface instance.
00862  *
00863  * @param message Message to enqueue.
00864  * @return message id after message has been queued
00865  * @exception MessageAlreadyQueuedException thrown if the message has already been
00866  * enqueued to an interface.
00867  */
00868 unsigned int
00869 Interface::msgq_enqueue_copy(Message *message)
00870 {
00871   if ( __write_access ) {
00872     throw InterfaceMessageEnqueueException(__type, __id);
00873   }
00874   if ( message == NULL ) {
00875     throw NullPointerException("Message may not be NULL");
00876   }
00877   
00878   if ( message_valid(message) ) {
00879     Message *mcopy = message->clone();
00880     mcopy->set_interface(this);
00881     mcopy->set_id(next_msg_id());
00882     __message_mediator->transmit(mcopy);
00883     unsigned int msgid = mcopy->id();
00884     mcopy->unref();
00885     message->set_id(msgid);
00886     return msgid;
00887   } else {
00888     throw InterfaceInvalidMessageException(this, message);
00889   }
00890 }
00891 
00892 
00893 /** Enqueue message.
00894  * This will enqueue the message without transmitting it via the
00895  * message mediator.
00896  *
00897  * This can only be called on a writing interface instance.
00898  * @param message message to enqueue
00899  */
00900 void
00901 Interface::msgq_append(Message *message)
00902 {
00903   if ( ! __write_access ) {
00904     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
00905                                         "reading instance of an interface (append).");
00906   }
00907 
00908   __message_queue->append(message);
00909 }
00910 
00911 
00912 /** Remove message from queue.
00913  * Removes the given message from the queue. Note that if you
00914  * unref()ed the message after insertion this will most likely delete
00915  * the object. It is not safe to use the message after removing it
00916  * from the queue in general.
00917  *
00918  * This can only be called on a writing interface instance.
00919  *
00920  * @param message Message to remove.
00921  */
00922 void
00923 Interface::msgq_remove(Message *message)
00924 {
00925   if ( ! __write_access ) {
00926     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
00927                                         "reading instance of an interface (remove msg).");
00928   }
00929 
00930   return __message_queue->remove(message);
00931 }
00932 
00933 
00934 /** Remove message from queue.
00935  * Removes message with the given ID from the queue.
00936  * @param message_id Message ID to remove.
00937  * This can only be called on a writing interface instance.
00938  */
00939 void
00940 Interface::msgq_remove(unsigned int message_id)
00941 {
00942   if ( ! __write_access ) {
00943     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
00944                                         "reading instance of an interface (remove id).");
00945   }
00946 
00947   return __message_queue->remove(message_id);
00948 }
00949 
00950 
00951 /** Get size of message queue.
00952  * This can only be called on a writing interface instance.
00953  * @return number of messages in queue.
00954  */
00955 unsigned int
00956 Interface::msgq_size()
00957 {
00958   if ( ! __write_access ) {
00959     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
00960                                         "reading instance of an interface (size).");
00961   }
00962 
00963   return __message_queue->size();
00964 }
00965 
00966 
00967 /** Check if queue is empty.
00968  * This can only be called on a writing interface instance.
00969  * @return true if queue is empty, false otherwise
00970  */
00971 bool
00972 Interface::msgq_empty()
00973 {
00974   if ( ! __write_access ) {
00975     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
00976                                         "reading instance of an interface (empty).");
00977   }
00978 
00979   return __message_queue->empty();
00980 }
00981 
00982 
00983 /** Flush all messages.
00984  * Deletes all messages from the queue.
00985  * This can only be called on a writing interface instance.
00986  */
00987 void
00988 Interface::msgq_flush()
00989 {
00990   if ( ! __write_access ) {
00991     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
00992                                         "reading instance of an interface (flush).");
00993   }
00994 
00995   __message_queue->flush();
00996 }
00997 
00998 
00999 /** Lock message queue.
01000  * Lock the message queue. You have to do this * before using the
01001  * iterator safely.
01002  *
01003  * This can only be called on a writing interface instance.
01004  */
01005 void
01006 Interface::msgq_lock()
01007 {
01008   if ( ! __write_access ) {
01009     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
01010                                         "reading instance of an interface (lock).");
01011   }
01012 
01013   __message_queue->lock();
01014 }
01015 
01016 
01017 /** Try to lock message queue.
01018  * Try to lock the message queue. Returns immediately and does not
01019  * wait for lock.
01020  *
01021  * This can only be called on a writing interface instance.
01022  * @return true, if the lock has been aquired, false otherwise.
01023  * @see lock()
01024  */
01025 bool
01026 Interface::msgq_try_lock()
01027 {
01028   if ( ! __write_access ) {
01029     throw InterfaceWriteDeniedException(__type, __id,
01030                                         "Cannot work on message queue on "
01031                                         "reading instance of an interface "
01032                                         "(msgq_try_lock).");
01033   }
01034 
01035   return __message_queue->try_lock();
01036 }
01037 
01038 
01039 /** Unlock message queue.
01040  * Give free the lock on the message queue.
01041  * This can only be called on a writing interface instance.
01042  */
01043 void
01044 Interface::msgq_unlock()
01045 {
01046   if ( ! __write_access ) {
01047     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
01048                                         "reading instance of an interface (unlock).");
01049   }
01050 
01051   __message_queue->unlock();
01052 }
01053 
01054 /** Get start iterator for message queue.
01055  * Not that you must have locked the queue before this operation!
01056  *
01057  * This can only be called on a writing interface instance.
01058  *
01059  * @return iterator to begin of message queue.
01060  * @exception NotLockedException thrown if message queue is not locked
01061  * during this operation.
01062  */
01063 MessageQueue::MessageIterator
01064 Interface::msgq_begin()
01065 {
01066   if ( ! __write_access ) {
01067     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
01068                                         "reading instance of an interface (begin).");
01069   }
01070 
01071   return __message_queue->begin();
01072 }
01073 
01074 
01075 /** Get end iterator for message queue.
01076  * Not that you must have locked the queue before this operation!
01077  *
01078  * This can only be called on a writing interface instance.
01079  *
01080  * @return iterator beyond end of message queue.
01081  * @exception NotLockedException thrown if message queue is not locked
01082  * during this operation.
01083  */
01084 MessageQueue::MessageIterator
01085 Interface::msgq_end()
01086 {
01087   if ( ! __write_access ) {
01088     throw InterfaceWriteDeniedException(__type, __id,
01089                                         "Cannot work on message queue on "
01090                                         "reading instance of an interface (end).");
01091   }
01092 
01093   return __message_queue->end();
01094 }
01095 
01096 
01097 /** Get the first message from the message queue.
01098  *
01099  * This can only be called on a writing interface instance.
01100  *
01101  * @return first message in queue or NULL if there is none
01102  */
01103 Message *
01104 Interface::msgq_first()
01105 {
01106   if ( ! __write_access ) {
01107     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
01108                                         "reading instance of an interface (first).");
01109   }
01110 
01111   return __message_queue->first();
01112 }
01113 
01114 /** Erase first message from queue.
01115  * This can only be called on a writing interface instance.
01116  */
01117 void
01118 Interface::msgq_pop()
01119 {
01120   if ( ! __write_access ) {
01121     throw InterfaceWriteDeniedException(__type, __id, "Cannot work on message queue on "
01122                                         "reading instance of an interface (pop).");
01123   }
01124 
01125   __message_queue->pop();
01126 }
01127 
01128 
01129 /** Get iterator over all fields of this interface instance.
01130  * @return field iterator pointing to the very first value
01131  */
01132 InterfaceFieldIterator
01133 Interface::fields()
01134 {
01135   return InterfaceFieldIterator(this, __fieldinfo_list);
01136 }
01137 
01138 
01139 /** Invalid iterator.
01140  * @return invalid iterator reprensenting the end.
01141  */
01142 InterfaceFieldIterator
01143 Interface::fields_end()
01144 {
01145   return InterfaceFieldIterator();
01146 }
01147 
01148 
01149 /** Get the number of fields in the interface.
01150  * @return the number of fields
01151  */
01152 unsigned int
01153 Interface::num_fields()
01154 {
01155   return __num_fields;
01156 }
01157 
01158 
01159 /** Resize buffer array.
01160  * This resizes the memory region used to store data buffers.
01161  * @param num_buffers number of buffers to resize to (memory is allocated
01162  * as necessary, 0 frees the memory area).
01163  * @exception Exception thrown if resizing the memory section fails
01164  */
01165 void
01166 Interface::resize_buffers(unsigned int num_buffers)
01167 {
01168   __data_mutex->lock();
01169   if (num_buffers == 0) {
01170     if (__buffers != NULL) {
01171       free(__buffers);
01172       __buffers = NULL;
01173       __num_buffers = 0;
01174     }
01175   } else {
01176     void *tmp = realloc(__buffers, num_buffers * data_size);
01177     if (tmp == NULL) {
01178       __data_mutex->unlock();
01179       throw Exception(errno, "Resizing buffers for interface %s failed", __uid);
01180     } else {
01181       __buffers     = tmp;
01182       __num_buffers = num_buffers;
01183     }
01184   }
01185   __data_mutex->unlock();
01186 }
01187 
01188 
01189 /** Get number of buffers.
01190  * @return number of buffers
01191  */
01192 unsigned int
01193 Interface::num_buffers() const
01194 {
01195   return __num_buffers;
01196 }
01197 
01198 
01199 /** Copy data from private memory to buffer.
01200  * @param buffer buffer number to copy to
01201  */
01202 void
01203 Interface::copy_shared_to_buffer(unsigned int buffer)
01204 {
01205   if (buffer >= __num_buffers) {
01206     throw OutOfBoundsException("Buffer ID out of bounds",
01207                                buffer, 0, __num_buffers);
01208   }
01209 
01210 
01211   __rwlock->lock_for_read();
01212   __data_mutex->lock();
01213 
01214   void *buf = (char *)__buffers + buffer * data_size;
01215 
01216   if ( __valid ) {
01217     memcpy(buf, __mem_data_ptr, data_size);
01218   } else {
01219     __data_mutex->unlock();
01220     __rwlock->unlock();
01221     throw InterfaceInvalidException(this, "copy_shared_to_buffer()");
01222   }
01223   __data_mutex->unlock();
01224   __rwlock->unlock();
01225 }
01226 
01227 
01228 /** Copy data from private memory to buffer.
01229  * @param buffer buffer number to copy to
01230  */
01231 void
01232 Interface::copy_private_to_buffer(unsigned int buffer)
01233 {
01234   if (buffer >= __num_buffers) {
01235     throw OutOfBoundsException("Buffer ID out of bounds",
01236                                buffer, 0, __num_buffers);
01237   }
01238 
01239 
01240   __data_mutex->lock();
01241   void *buf = (char *)__buffers + buffer * data_size;
01242   memcpy(buf, data_ptr, data_size);
01243   __data_mutex->unlock();
01244 }
01245 
01246 
01247 
01248 /** Copy data from buffer to private memory.
01249  * @param buffer buffer number to copy to
01250  */
01251 void
01252 Interface::read_from_buffer(unsigned int buffer)
01253 {
01254   if (buffer >= __num_buffers) {
01255     throw OutOfBoundsException("Buffer ID out of bounds",
01256                                buffer, 0, __num_buffers);
01257   }
01258 
01259   __data_mutex->lock();
01260   void *buf = (char *)__buffers + buffer * data_size;
01261   memcpy(data_ptr, buf, data_size);
01262   __data_mutex->unlock();
01263 }
01264 
01265 
01266 /** Compare buffer to private memory.
01267  * @param buffer buffer number of buffer to compare to private memory
01268  * @return returns a number less than, equal to, or greater than zero
01269  * if the shared buffer if less than, equal to, or greater than the
01270  * private buffer respectively.
01271  */
01272 int
01273 Interface::compare_buffers(unsigned int buffer)
01274 {
01275   if (buffer >= __num_buffers) {
01276     throw OutOfBoundsException("Buffer ID out of bounds",
01277                                buffer, 0, __num_buffers);
01278   }
01279 
01280   __data_mutex->lock();
01281   void *buf = (char *)__buffers + buffer * data_size;
01282   int rv = memcmp(buf, data_ptr, data_size);
01283   __data_mutex->unlock();
01284 
01285   return rv;
01286 }
01287 
01288 
01289 /** Parse UID to type and ID strings.
01290  * Note that the returned values (type and id) must be freed once they are
01291  * no longer used. Also verifies lengths of the type and id strings.
01292  * @param uid UID to parse
01293  * @param type upon return contains the type part of the UID, must be freed
01294  * @param id upon return contains the ID part, must be freed
01295  */
01296 void
01297 Interface::parse_uid(const char *uid, char **type, char **id)
01298 {
01299   regex_t re;
01300   int ec = 0;
01301 // Requires in parse_uid()
01302 #define str(s) #s
01303 #define xstr(s) str(s)
01304   if ((ec = regcomp(&re,
01305                     "^([a-zA-Z0-9]{1," xstr(__INTERFACE_TYPE_SIZE) "})::"
01306                     "([a-zA-Z0-9 _\\.-]{1," xstr(__INTERFACE_ID_SIZE) "})$",
01307                     REG_EXTENDED)) != 0) {
01308     char errbuf[1024];
01309     regerror(ec, &re, errbuf, 1024);
01310     throw Exception("Failed to created regular expression to parse UID (%s)",
01311                     errbuf);
01312   }
01313   regmatch_t matches[3];
01314   if (regexec(&re, uid, 3, matches, 0) != 0) {
01315     regfree(&re);
01316     throw Exception("Failed to match UID %s, format error.", uid);
01317   }
01318 
01319   *type = strndup(&(uid[matches[1].rm_so]), matches[1].rm_eo - matches[1].rm_so);
01320   *id   = strndup(&(uid[matches[2].rm_so]), matches[2].rm_eo - matches[2].rm_so);
01321 }
01322 
01323 } // end namespace fawkes