Fawkes API
Fawkes Development Version
|
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