Fawkes API  Fawkes Development Version
interface.h
00001 
00002 /***************************************************************************
00003  *  interface.h - BlackBoard Interface
00004  *
00005  *  Created: Mon Oct 09 18:34:11 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 #ifndef __INTERFACE_H_
00025 #define __INTERFACE_H_
00026 
00027 #include <interface/message.h>
00028 #include <interface/message_queue.h>
00029 #include <core/exception.h>
00030 
00031 #include <cstddef>
00032 #include <list>
00033 #define __STD_LIMIT_MACROS
00034 #include <stdint.h>
00035 
00036 #define __INTERFACE_TYPE_SIZE   32
00037 #define __INTERFACE_ID_SIZE     32
00038 // We use MD5 as interface hash
00039 #define __INTERFACE_HASH_SIZE   16
00040 //  UID is:                                   type  ::   id
00041 #define __INTERFACE_UID_SIZE __INTERFACE_TYPE_SIZE + 2 + __INTERFACE_ID_SIZE
00042 
00043 namespace fawkes {
00044 #if 0 /* just to make Emacs auto-indent happy */
00045 }
00046 #endif
00047 
00048 class RefCountRWLock;
00049 class InterfaceMediator;
00050 class MessageMediator;
00051 class Time;
00052 class Clock;
00053 class Mutex;
00054 
00055 class InterfaceWriteDeniedException : public Exception
00056 {
00057  public:
00058   InterfaceWriteDeniedException(const char *type, const char *id, const char *msg);
00059 };
00060 
00061 class InterfaceMessageEnqueueException : public Exception
00062 {
00063  public:
00064   InterfaceMessageEnqueueException(const char *type, const char *id);
00065 };
00066 
00067 class InterfaceInvalidMessageException : public Exception
00068 {
00069  public:
00070   InterfaceInvalidMessageException(const Interface *interface, const Message *message);
00071 };
00072 
00073 
00074 class InterfaceInvalidException : public Exception
00075 {
00076  public:
00077   InterfaceInvalidException(const Interface *interface, const char *method);
00078 };
00079 
00080 class Interface
00081 {
00082  friend class BlackBoardInterfaceManager;
00083  friend class BlackBoardInstanceFactory;
00084  friend class BlackBoardMessageManager;
00085  friend class BlackBoardInterfaceProxy;
00086 
00087  public:
00088   virtual ~Interface();
00089 
00090   bool                    oftype(const char *interface_type) const;
00091   const void *            datachunk() const;
00092   unsigned int            datasize() const;
00093   const char *            type() const;
00094   const char *            id() const;
00095   const char *            uid() const;
00096   unsigned short          serial() const;
00097   unsigned int            mem_serial() const;
00098   bool                    operator== (Interface &comp) const;
00099   const unsigned char *   hash() const;
00100   size_t                  hash_size() const;
00101   const char *            hash_printable() const;
00102   bool                    is_writer() const;
00103   void                    set_validity(bool valid);
00104   bool                    is_valid() const;
00105 
00106   void                    set_from_chunk(void *chunk);
00107 
00108   virtual Message *       create_message(const char *type) const = 0;
00109   virtual void            copy_values(const Interface *interface) = 0;
00110   virtual const char *    enum_tostring(const char *enumtype, int val) const = 0;
00111 
00112   void                    resize_buffers(unsigned int num_buffers);
00113   unsigned int            num_buffers() const;
00114   void                    copy_shared_to_buffer(unsigned int buffer);
00115   void                    copy_private_to_buffer(unsigned int buffer);
00116   void                    read_from_buffer(unsigned int buffer);
00117   int                     compare_buffers(unsigned int buffer);
00118 
00119   void          read();
00120   void          write();
00121 
00122   bool          has_writer() const;
00123   unsigned int  num_readers() const;
00124 
00125   bool          changed() const;
00126   const Time *  timestamp() const;
00127   void          set_auto_timestamping(bool enabled);
00128   void          set_timestamp(const Time *t = NULL);
00129   void          set_clock(Clock *clock);
00130 
00131   std::list<const char *> get_message_types();
00132 
00133   unsigned int  msgq_enqueue(Message *message);
00134   unsigned int  msgq_enqueue_copy(Message *message);
00135   void          msgq_remove(Message *message);
00136   void          msgq_remove(unsigned int message_id);
00137   unsigned int  msgq_size();
00138   void          msgq_flush();
00139   void          msgq_lock();
00140   bool          msgq_try_lock();
00141   void          msgq_unlock();
00142   void          msgq_pop();
00143   Message *     msgq_first();
00144   bool          msgq_empty();
00145 
00146   /** Check if first message has desired type.
00147    * @return true, if message has desired type, false otherwise
00148    */
00149   template <class MessageType>
00150     bool           msgq_first_is();
00151 
00152   /** Get first message casted to the desired type.
00153    * @return message casted to desired type
00154    * @exception TypeMismatchException thrown if message is not of desired type
00155    */
00156   template <class MessageType>
00157     MessageType *  msgq_first();
00158 
00159   /** Get first message casted to the desired type.
00160    * @param msg reference to pointer to message of desired type, upon successful
00161    * return points to the message. 
00162    * @return message casted to desired type (same as msg parameter)
00163    * @exception TypeMismatchException thrown if message is not of desired type
00164    */
00165   template <class MessageType>
00166     MessageType *  msgq_first(MessageType *&msg);
00167 
00168   /** Get first message casted to the desired type without exceptions.
00169    * This method allows to combine a call to msgq_first_is() and msgq_first()
00170    * into a single call.
00171    * @param msg reference to pointer to message of desired type, upon successful
00172    * return points to the message. 
00173    * @return pointer to message if it is of the desired type, 0 otherwise
00174    */
00175   template <class MessageType>
00176     MessageType * msgq_first_safe(MessageType *&msg) throw();
00177 
00178   MessageQueue::MessageIterator  msgq_begin();
00179   MessageQueue::MessageIterator  msgq_end();
00180 
00181   /* Introspection */
00182 
00183   /** Message info list */
00184   struct interface_messageinfo_t {
00185     const char              *type;   /**< the type of the message */
00186     interface_messageinfo_t *next;   /**< the next field, NULL if last */
00187   };
00188 
00189   InterfaceFieldIterator fields();
00190   InterfaceFieldIterator fields_end();
00191 
00192   unsigned int num_fields();
00193 
00194   /* Convenience */
00195   static void parse_uid(const char *uid, char **type, char **id);
00196 
00197  protected:
00198   Interface();
00199   virtual bool  message_valid(const Message *message) const = 0;
00200 
00201   void set_hash(unsigned char *ihash);
00202   void add_fieldinfo(interface_fieldtype_t type, const char *name,
00203                      size_t length, void *value, const char *enumtype = 0);
00204   void add_messageinfo(const char *name);
00205 
00206   void         *data_ptr;
00207   unsigned int  data_size;
00208   bool          data_changed;
00209 
00210   /** Timestamp data, must be present and first entries for each interface
00211    * data structs! This leans on timeval struct. */
00212   typedef struct {
00213     int64_t timestamp_sec;      /**< time in seconds since Unix epoch */
00214     int64_t timestamp_usec;     /**< additional time microseconds */
00215   } interface_data_ts_t;
00216   interface_data_ts_t  *data_ts;
00217 
00218  private:
00219   void msgq_append(Message *message);
00220   void set_type_id(const char *type, const char *id);
00221   void set_instance_serial(unsigned short instance_serial);
00222   void set_mediators(InterfaceMediator *iface_mediator,
00223                                    MessageMediator *msg_mediator);
00224   void set_memory(unsigned int serial, void *real_ptr, void *data_ptr);
00225   void set_readwrite(bool write_access, RefCountRWLock *rwlock);
00226 
00227   inline unsigned int next_msg_id()
00228   {
00229     return (__instance_serial << 16) | ++__next_message_id;
00230   }
00231 
00232   char               __type[__INTERFACE_TYPE_SIZE + 1];
00233   char               __id[__INTERFACE_ID_SIZE + 1];
00234   char               __uid[__INTERFACE_UID_SIZE + 1];
00235   unsigned char      __hash[__INTERFACE_HASH_SIZE];
00236   char               __hash_printable[__INTERFACE_HASH_SIZE * 2 + 1];
00237 
00238   unsigned short     __instance_serial;
00239   bool               __valid;
00240 
00241   void *             __mem_data_ptr;
00242   void *             __mem_real_ptr;
00243   unsigned int       __mem_serial;
00244   bool               __write_access;
00245 
00246   void *             __buffers;
00247   unsigned int       __num_buffers;
00248 
00249   Mutex             *__data_mutex;
00250   RefCountRWLock    *__rwlock;
00251 
00252   InterfaceMediator *__interface_mediator;
00253   MessageMediator   *__message_mediator;
00254   MessageQueue      *__message_queue;
00255   unsigned short     __next_message_id;
00256 
00257   interface_fieldinfo_t   *__fieldinfo_list;
00258   interface_messageinfo_t *__messageinfo_list;
00259 
00260   unsigned int       __num_fields;
00261 
00262   Clock             *__clock;
00263   Time              *__timestamp;
00264   Time              *__local_read_timestamp;
00265   bool               __auto_timestamping;
00266 };
00267 
00268 
00269 template <class MessageType>
00270 MessageType *
00271 Interface::msgq_first()
00272 {
00273   MessageType *m = dynamic_cast<MessageType *>(__message_queue->first());
00274   if (m) {
00275     return m;
00276   } else {
00277     throw TypeMismatchException("Message is not of desired type");
00278   }
00279 }
00280 
00281 
00282 template <class MessageType>
00283 MessageType *
00284 Interface::msgq_first(MessageType *&msg)
00285 {
00286   msg = this->msgq_first<MessageType>();
00287   return msg;
00288 }
00289 
00290 
00291 template <class MessageType>
00292 MessageType *
00293 Interface::msgq_first_safe(MessageType *&msg) throw()
00294 {
00295   msg = dynamic_cast<MessageType *>(__message_queue->first());
00296   return msg;
00297 }
00298 
00299 
00300 /** Check if first message has desired type.
00301  * @return true, if message has desired type, false otherwise
00302  */
00303 template <class MessageType>
00304 bool
00305 Interface::msgq_first_is()
00306 {
00307   return (dynamic_cast<MessageType *>(__message_queue->first()) != 0);
00308 }
00309 
00310 
00311 /** Interface destructor function for the shared library.
00312  * Do not use directly. Use EXPORT_INTERFACE macro.
00313  * @param interface Interface to destroy
00314  */
00315 typedef void         (* InterfaceDestroyFunc)  (Interface *interface);
00316 
00317 /** Interface generator function for the shared library
00318  * Do not use directly. Use EXPORT_INTERFACE macro.
00319  */
00320 typedef Interface *  (* InterfaceFactoryFunc)  (void);
00321 
00322 
00323 /** Friend for interface generator function. */
00324 #define INTERFACE_MGMT_FRIENDS(interface_class)                         \
00325   friend Interface * private_new##interface_class();                    \
00326   friend void private_delete##interface_class(interface_class *interface);
00327 
00328 /** Interface generator function for this plugin.
00329  * @return an instance of the desired interface
00330  */
00331 #define INTERFACE_GENERATOR(interface_class)                    \
00332   Interface *                                                   \
00333   private_new##interface_class()                                \
00334   {                                                             \
00335     return new interface_class();                               \
00336   }
00337 
00338 
00339 /** Interface delete function for this plugin.
00340  * @return an instance of the desired interface
00341  */
00342 #define INTERFACE_DELETER(interface_class)                      \
00343   void                                                          \
00344   private_delete##interface_class(interface_class *interface)   \
00345   {                                                             \
00346     delete interface;                                           \
00347   }
00348 
00349 
00350 /** Interface factory function.
00351  * @return an instance of the desired interface
00352  */
00353 #define INTERFACE_FACTORY(interface_class)                      \
00354   extern "C"                                                    \
00355   Interface *                                                   \
00356   interface_factory()                                           \
00357   {                                                             \
00358     return private_new##interface_class();                      \
00359   }
00360 
00361 
00362 /** Interface destruction function.
00363  * @param interface The interface that is to be destroyed.
00364  */
00365 #define INTERFACE_DESTROY(interface_class)              \
00366   extern "C"                                            \
00367   void                                                  \
00368   interface_destroy(interface_class *interface)         \
00369   {                                                     \
00370     private_delete##interface_class(interface);         \
00371   }
00372 
00373 /** Export interface.
00374  * This will create appropriate interface factory and destroy functions.
00375  */
00376 #define EXPORT_INTERFACE(interface_class) \
00377   INTERFACE_GENERATOR(interface_class)    \
00378   INTERFACE_DELETER(interface_class)      \
00379   INTERFACE_FACTORY(interface_class)      \
00380   INTERFACE_DESTROY(interface_class)
00381 
00382 } // end namespace fawkes
00383 
00384 #endif