Fawkes API  Fawkes Development Version
message.cpp
00001 
00002 /***************************************************************************
00003  *  message.cpp - BlackBoard message
00004  *
00005  *  Created: Tue Oct 17 00:52:34 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/message.h>
00025 #include <interface/interface.h>
00026 
00027 #include <core/threading/thread.h>
00028 #include <core/threading/mutex.h>
00029 #include <core/exceptions/software.h>
00030 #include <utils/time/time.h>
00031 
00032 #include <cstring>
00033 #include <cstdlib>
00034 #include <unistd.h>
00035 
00036 namespace fawkes {
00037 #if 0 /* just to make Emacs auto-indent happy */
00038 }
00039 #endif
00040 
00041 /** @class Message <interface/message.h>
00042  * Base class for all messages passed through interfaces in Fawkes BlackBoard.
00043  * Do not use directly, but instead use the interface generator to generate
00044  * an interface with accompanying messages.
00045  *
00046  * The sender ID of the message is automatically determined and is the instance
00047  * serial of the interface where the message was enqueued using
00048  * Interface::msgq_enqueue().
00049  *
00050  * @author Tim Niemueller
00051  */
00052 
00053 /** @var Message::data_ptr
00054  * Pointer to memory that contains local data. This memory has to be allocated
00055  * by deriving classes with the approppriate size!
00056  */
00057 
00058 /** @var Message::data_size
00059  * Size of memory needed to hold all data. This has to be set by deriving classes
00060  * to the appropriate value.
00061  */
00062 
00063 
00064 /** Constructor.
00065  * @param type string representation of the message type
00066  */
00067 Message::Message(const char *type)
00068 {
00069   __fieldinfo_list = NULL;
00070 
00071   __message_id = 0;
00072   __hops       = 0;
00073   __enqueued   = false;
00074   __num_fields = 0;
00075   data_ptr     = NULL;
00076   data_ts      = NULL;
00077   _sender_id   = 0;
00078   _type        = strdup(type);
00079   __time_enqueued = new Time();
00080 
00081   _transmit_via_iface              = NULL;
00082   sender_interface_instance_serial = 0;
00083   recipient_interface_mem_serial   = 0;
00084 
00085   Thread *t = Thread::current_thread_noexc();
00086   if ( t ) {
00087     _sender_thread_name = strdup(t->name());
00088   } else {
00089     _sender_thread_name    = strdup("Unknown");
00090   }
00091 }
00092 
00093 
00094 /** Copy constructor.
00095  * @param mesg Message to copy.
00096  */
00097 Message::Message(const Message &mesg)
00098 {
00099   __message_id = 0;
00100   __hops       = mesg.__hops;
00101   __enqueued   = false;
00102   __num_fields = mesg.__num_fields;
00103   data_size    = mesg.data_size;
00104   data_ptr     = malloc(data_size);
00105   data_ts      = (message_data_ts_t *)data_ptr;
00106   _sender_id   = 0;
00107   _type        = strdup(mesg._type);
00108   __time_enqueued = new Time(mesg.__time_enqueued);
00109 
00110   _transmit_via_iface              = NULL;
00111   sender_interface_instance_serial = 0;
00112   recipient_interface_mem_serial   = 0;
00113 
00114   memcpy(data_ptr, mesg.data_ptr, data_size);
00115 
00116   interface_fieldinfo_t  *info_src  = mesg.__fieldinfo_list;
00117   interface_fieldinfo_t **info_dest = &__fieldinfo_list;
00118   while ( info_src ) {
00119     interface_fieldinfo_t *new_info = (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
00120     memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
00121     *info_dest = new_info;
00122 
00123     info_dest = &((*info_dest)->next);
00124     info_src  = info_src->next;
00125   }
00126 
00127   Thread *t = Thread::current_thread_noexc();
00128   if ( t ) {
00129     _sender_thread_name = strdup(t->name());
00130   } else {
00131     _sender_thread_name    = strdup("Unknown");
00132   }
00133 }
00134 
00135 
00136 /** Copy constructor.
00137  * @param mesg Message to copy.
00138  */
00139 Message::Message(const Message *mesg)
00140 {
00141   __message_id = 0;
00142   __hops       = mesg->__hops;
00143   __enqueued   = false;
00144   __num_fields = mesg->__num_fields;
00145   data_size    = mesg->data_size;
00146   data_ptr     = malloc(data_size);
00147   data_ts      = (message_data_ts_t *)data_ptr;
00148   _sender_id   = 0;
00149   _type        = strdup(mesg->_type);
00150   _transmit_via_iface              = NULL;
00151   sender_interface_instance_serial = 0;
00152   recipient_interface_mem_serial   = 0;
00153   __time_enqueued = new Time(mesg->__time_enqueued);
00154 
00155   memcpy(data_ptr, mesg->data_ptr, data_size);
00156 
00157   interface_fieldinfo_t  *info_src  = mesg->__fieldinfo_list;
00158   interface_fieldinfo_t **info_dest = &__fieldinfo_list;
00159   while ( info_src ) {
00160     interface_fieldinfo_t *new_info = (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
00161     memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
00162     *info_dest = new_info;
00163 
00164     info_dest = &((*info_dest)->next);
00165     info_src  = info_src->next;
00166   }
00167 
00168   Thread *t = Thread::current_thread_noexc();
00169   if ( t ) {
00170     _sender_thread_name    = strdup(t->name());
00171   } else {
00172     _sender_thread_name    = strdup("Unknown");
00173   }
00174 }
00175 
00176 
00177 /** Destructor. */
00178 Message::~Message()
00179 {
00180   free(_sender_thread_name);
00181   free(_type);
00182   delete __time_enqueued;
00183 
00184   interface_fieldinfo_t *infol = __fieldinfo_list;
00185   while ( infol ) {
00186     __fieldinfo_list = __fieldinfo_list->next;
00187     free(infol);
00188     infol = __fieldinfo_list;
00189   }
00190 }
00191 
00192 
00193 /** Get message ID.
00194  * @return message ID.
00195  */
00196 unsigned int
00197 Message::id() const
00198 {
00199   return __message_id;
00200 }
00201 
00202 
00203 /** Get number of hops.
00204  * @return number of hops
00205  */
00206 unsigned int
00207 Message::hops() const
00208 {
00209   return __hops;
00210 }
00211 
00212 
00213 /** Set message ID.
00214  * @param message_id message ID
00215  */
00216 void
00217 Message::set_id(unsigned int message_id)
00218 {
00219   __message_id = message_id;
00220 }
00221 
00222 
00223 /** Set number of hops.
00224  * @param hops number of hops
00225  */
00226 void
00227 Message::set_hops(unsigned int hops)
00228 {
00229   __hops=hops;
00230 }
00231 
00232 
00233 /** Mark message as being enqueued. */
00234 void
00235 Message::mark_enqueued()
00236 {
00237   __time_enqueued->stamp();
00238   long sec = 0, usec = 0;
00239   __time_enqueued->get_timestamp(sec, usec);
00240   data_ts->timestamp_sec  = sec;
00241   data_ts->timestamp_usec = usec;
00242 
00243   __enqueued = true;
00244 }
00245 
00246 
00247 /** Check is message has been enqueued.
00248  * @return true if the message has already been enqueued, false otherwise
00249  */
00250 bool
00251 Message::enqueued() const
00252 {
00253   return __enqueued;
00254 }
00255 
00256 
00257 /** Get time when message was enqueued.
00258  * Note that this assumes synchronized clocks between sender and receiver.
00259  * Problematic in this regard are remote network connections. For one the
00260  * system times of the two system can diverge, for the other the clock on
00261  * only one of the systems may be simulated.
00262  * @return timestamp when message was enqueued.
00263  */
00264 const Time *
00265 Message::time_enqueued() const
00266 {
00267   return __time_enqueued;
00268 }
00269 
00270 
00271 /** Get recipient memory serial.
00272  * @return Interface memory serial of the recipient interface.
00273  */
00274 unsigned int
00275 Message::recipient() const
00276 {
00277   return recipient_interface_mem_serial;
00278 }
00279 
00280 /** Get pointer to data.
00281  * Avoid usage.
00282  * @return pointer to internal data
00283  */
00284 const void *
00285 Message::datachunk() const
00286 {
00287   return data_ptr;
00288 }
00289 
00290 
00291 /** Get size of data.
00292  * @return size in bytes of data
00293  */
00294 unsigned int
00295 Message::datasize() const
00296 {
00297   return data_size;
00298 }
00299 
00300 
00301 /** Set from raw data chunk.
00302  * This sets the internal storage to the given chunk. The chunk must be exactly
00303  * of the size returned by datasize().
00304  * @param chunk chunk containing the data exactly of the size returned by datasize()
00305  */
00306 void
00307 Message::set_from_chunk(const void *chunk)
00308 {
00309   memcpy(data_ptr, chunk, data_size);
00310   __time_enqueued->set_time(data_ts->timestamp_sec, data_ts->timestamp_usec);
00311 }
00312 
00313 
00314 /** Assign this message to given message.
00315  * Data is copied over from message if data sizes are the same.
00316  * @param m Message to copy
00317  * @return reference to current instance
00318  */
00319 Message &
00320 Message::operator=  (const Message & m)
00321 {
00322   if ( data_size == m.data_size ) {
00323     memcpy(data_ptr, m.data_ptr, data_size);
00324     __time_enqueued->set_time(data_ts->timestamp_sec, data_ts->timestamp_usec);
00325   }
00326 
00327   return *this;
00328 }
00329 
00330 
00331 /** Get sender of message.
00332  * @return name of sending thread
00333  */
00334 const char *
00335 Message::sender_thread_name() const
00336 {
00337   return _sender_thread_name;
00338 }
00339 
00340 
00341 /** Get ID of sender.
00342  * @return name of sending thread.
00343  */
00344 unsigned int
00345 Message::sender_id() const
00346 {
00347   return _sender_id;
00348 }
00349 
00350 
00351 /** Set transmitting interface.
00352  * Called by Message Manager
00353  * @param iface transmitting interface
00354  */
00355 void
00356 Message::set_interface(Interface *iface)
00357 {
00358   _transmit_via_iface = iface;
00359   _sender_id = iface->serial();
00360   recipient_interface_mem_serial = iface->mem_serial();
00361 }
00362 
00363 
00364 /** Get transmitting interface.
00365  * @return transmitting interface, or NULL if message has not been enqueued, yet.
00366  */
00367 Interface *
00368 Message::interface() const
00369 {
00370   return _transmit_via_iface;
00371 }
00372 
00373 
00374 /** Get message type.
00375  * @return textual representation of the interface type
00376  */
00377 const char *
00378 Message::type() const
00379 {
00380   return _type;
00381 }
00382 
00383 
00384 /** Get iterator over all fields of this interface instance.
00385  * @return field iterator pointing to the very first value
00386  */
00387 InterfaceFieldIterator
00388 Message::fields()
00389 {
00390   return InterfaceFieldIterator(_transmit_via_iface, __fieldinfo_list);
00391 }
00392 
00393 
00394 /** Invalid iterator.
00395  * @return invalid iterator reprensenting the end.
00396  */
00397 InterfaceFieldIterator
00398 Message::fields_end()
00399 {
00400   return InterfaceFieldIterator();
00401 }
00402 
00403 
00404 /** Get the number of fields in the message.
00405  * @return the number of fields
00406  */
00407 unsigned int
00408 Message::num_fields() const
00409 {
00410   return __num_fields;
00411 }
00412 
00413 
00414 /** Clone this message.
00415  * Shall be implemented by every sub-class to return a message of proper type.
00416  * @return new message cloned from this instance
00417  */
00418 Message *
00419 Message::clone() const
00420 {
00421   return new Message(this);
00422 }
00423 
00424 /** Add an entry to the info list.
00425  * Never use directly, use the interface generator instead. The info list
00426  * is used for introspection purposes to allow for iterating over all fields
00427  * of an interface.
00428  * @param type field type
00429  * @param name name of the field, this is referenced, not copied
00430  * @param length length of the field
00431  * @param value pointer to the value in the data struct
00432  * @param enumtype in case the type parameter is enum the name of the enum type
00433  */
00434 void
00435 Message::add_fieldinfo(interface_fieldtype_t type, const char *name,
00436                        size_t length, void *value, const char *enumtype)
00437 {
00438   interface_fieldinfo_t *infol = __fieldinfo_list;
00439   interface_fieldinfo_t *newinfo = (interface_fieldinfo_t *)malloc(sizeof(interface_fieldinfo_t));
00440 
00441   newinfo->type     = type;
00442   newinfo->enumtype = enumtype;
00443   newinfo->name     = name;
00444   newinfo->length   = length;
00445   newinfo->value    = value;
00446   newinfo->next     = NULL;
00447 
00448   if ( infol == NULL ) {
00449     // first entry
00450     __fieldinfo_list = newinfo;
00451   } else {
00452     // append to list
00453     while ( infol->next != NULL ) {
00454       infol = infol->next;
00455     }
00456     infol->next = newinfo;
00457   }
00458 
00459   ++__num_fields;
00460 }
00461 
00462 } // end namespace fawkes