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