Fawkes API  Fawkes Development Version
message.cpp
1 
2 /***************************************************************************
3  * message.cpp - BlackBoard message
4  *
5  * Created: Tue Oct 17 00:52:34 2006
6  * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <interface/message.h>
25 #include <interface/interface.h>
26 
27 #include <core/threading/thread.h>
28 #include <core/threading/mutex.h>
29 #include <core/exceptions/software.h>
30 #include <utils/time/time.h>
31 
32 #include <cstring>
33 #include <cstdlib>
34 #include <unistd.h>
35 
36 namespace fawkes {
37 #if 0 /* just to make Emacs auto-indent happy */
38 }
39 #endif
40 
41 /** @class Message <interface/message.h>
42  * Base class for all messages passed through interfaces in Fawkes BlackBoard.
43  * Do not use directly, but instead use the interface generator to generate
44  * an interface with accompanying messages.
45  *
46  * The sender ID of the message is automatically determined and is the instance
47  * serial of the interface where the message was enqueued using
48  * Interface::msgq_enqueue().
49  *
50  * @author Tim Niemueller
51  */
52 
53 /** @var Message::data_ptr
54  * Pointer to memory that contains local data. This memory has to be allocated
55  * by deriving classes with the approppriate size!
56  */
57 
58 /** @var Message::data_size
59  * Size of memory needed to hold all data. This has to be set by deriving classes
60  * to the appropriate value.
61  */
62 
63 
64 /** Constructor.
65  * @param type string representation of the message type
66  */
67 Message::Message(const char *type)
68 {
69  __fieldinfo_list = NULL;
70 
71  __message_id = 0;
72  __hops = 0;
73  __enqueued = false;
74  __num_fields = 0;
75  data_ptr = NULL;
76  data_ts = NULL;
77  _sender_id = 0;
78  _type = strdup(type);
79  __time_enqueued = new Time();
80 
81  _transmit_via_iface = NULL;
82  sender_interface_instance_serial = 0;
83  recipient_interface_mem_serial = 0;
84 
86  if ( t ) {
87  _sender_thread_name = strdup(t->name());
88  } else {
89  _sender_thread_name = strdup("Unknown");
90  }
91 }
92 
93 
94 /** Copy constructor.
95  * @param mesg Message to copy.
96  */
98 {
99  __message_id = 0;
100  __hops = mesg.__hops;
101  __enqueued = false;
102  __num_fields = mesg.__num_fields;
103  data_size = mesg.data_size;
104  data_ptr = malloc(data_size);
106  _sender_id = 0;
107  _type = strdup(mesg._type);
108  __time_enqueued = new Time(mesg.__time_enqueued);
109 
110  _transmit_via_iface = NULL;
111  sender_interface_instance_serial = 0;
112  recipient_interface_mem_serial = 0;
113 
114  memcpy(data_ptr, mesg.data_ptr, data_size);
115 
116  interface_fieldinfo_t *info_src = mesg.__fieldinfo_list;
117  interface_fieldinfo_t **info_dest = &__fieldinfo_list;
118  while ( info_src ) {
120  memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
121  *info_dest = new_info;
122 
123  info_dest = &((*info_dest)->next);
124  info_src = info_src->next;
125  }
126 
128  if ( t ) {
129  _sender_thread_name = strdup(t->name());
130  } else {
131  _sender_thread_name = strdup("Unknown");
132  }
133 }
134 
135 
136 /** Copy constructor.
137  * @param mesg Message to copy.
138  */
140 {
141  __message_id = 0;
142  __hops = mesg->__hops;
143  __enqueued = false;
144  __num_fields = mesg->__num_fields;
145  data_size = mesg->data_size;
146  data_ptr = malloc(data_size);
148  _sender_id = 0;
149  _type = strdup(mesg->_type);
150  _transmit_via_iface = NULL;
151  sender_interface_instance_serial = 0;
152  recipient_interface_mem_serial = 0;
153  __time_enqueued = new Time(mesg->__time_enqueued);
154 
155  memcpy(data_ptr, mesg->data_ptr, data_size);
156 
157  interface_fieldinfo_t *info_src = mesg->__fieldinfo_list;
158  interface_fieldinfo_t **info_dest = &__fieldinfo_list;
159  while ( info_src ) {
161  memcpy(new_info, info_src, sizeof(interface_fieldinfo_t));
162  *info_dest = new_info;
163 
164  info_dest = &((*info_dest)->next);
165  info_src = info_src->next;
166  }
167 
169  if ( t ) {
170  _sender_thread_name = strdup(t->name());
171  } else {
172  _sender_thread_name = strdup("Unknown");
173  }
174 }
175 
176 
177 /** Destructor. */
179 {
180  free(_sender_thread_name);
181  free(_type);
182  delete __time_enqueued;
183 
184  interface_fieldinfo_t *infol = __fieldinfo_list;
185  while ( infol ) {
186  __fieldinfo_list = __fieldinfo_list->next;
187  free(infol);
188  infol = __fieldinfo_list;
189  }
190 }
191 
192 
193 /** Get message ID.
194  * @return message ID.
195  */
196 unsigned int
197 Message::id() const
198 {
199  return __message_id;
200 }
201 
202 
203 /** Get number of hops.
204  * @return number of hops
205  */
206 unsigned int
208 {
209  return __hops;
210 }
211 
212 
213 /** Set message ID.
214  * @param message_id message ID
215  */
216 void
217 Message::set_id(unsigned int message_id)
218 {
219  __message_id = message_id;
220 }
221 
222 
223 /** Set number of hops.
224  * @param hops number of hops
225  */
226 void
227 Message::set_hops(unsigned int hops)
228 {
229  __hops=hops;
230 }
231 
232 
233 /** Mark message as being enqueued. */
234 void
236 {
237  __time_enqueued->stamp();
238  long sec = 0, usec = 0;
239  __time_enqueued->get_timestamp(sec, usec);
240  data_ts->timestamp_sec = sec;
241  data_ts->timestamp_usec = usec;
242 
243  __enqueued = true;
244 }
245 
246 
247 /** Check is message has been enqueued.
248  * @return true if the message has already been enqueued, false otherwise
249  */
250 bool
252 {
253  return __enqueued;
254 }
255 
256 
257 /** Get time when message was enqueued.
258  * Note that this assumes synchronized clocks between sender and receiver.
259  * Problematic in this regard are remote network connections. For one the
260  * system times of the two system can diverge, for the other the clock on
261  * only one of the systems may be simulated.
262  * @return timestamp when message was enqueued.
263  */
264 const Time *
266 {
267  return __time_enqueued;
268 }
269 
270 
271 /** Get recipient memory serial.
272  * @return Interface memory serial of the recipient interface.
273  */
274 unsigned int
276 {
277  return recipient_interface_mem_serial;
278 }
279 
280 /** Get pointer to data.
281  * Avoid usage.
282  * @return pointer to internal data
283  */
284 const void *
286 {
287  return data_ptr;
288 }
289 
290 
291 /** Get size of data.
292  * @return size in bytes of data
293  */
294 unsigned int
296 {
297  return data_size;
298 }
299 
300 
301 /** Set from raw data chunk.
302  * This sets the internal storage to the given chunk. The chunk must be exactly
303  * of the size returned by datasize().
304  * @param chunk chunk containing the data exactly of the size returned by datasize()
305  */
306 void
307 Message::set_from_chunk(const void *chunk)
308 {
309  memcpy(data_ptr, chunk, data_size);
310  __time_enqueued->set_time(data_ts->timestamp_sec, data_ts->timestamp_usec);
311 }
312 
313 
314 /** Assign this message to given message.
315  * Data is copied over from message if data sizes are the same.
316  * @param m Message to copy
317  * @return reference to current instance
318  */
319 Message &
321 {
322  if ( data_size == m.data_size ) {
323  memcpy(data_ptr, m.data_ptr, data_size);
324  __time_enqueued->set_time(data_ts->timestamp_sec, data_ts->timestamp_usec);
325  }
326 
327  return *this;
328 }
329 
330 
331 /** Get sender of message.
332  * @return name of sending thread
333  */
334 const char *
336 {
337  return _sender_thread_name;
338 }
339 
340 
341 /** Get ID of sender.
342  * @return name of sending thread.
343  */
344 unsigned int
346 {
347  return _sender_id;
348 }
349 
350 
351 /** Set transmitting interface.
352  * Called by Message Manager
353  * @param iface transmitting interface
354  */
355 void
356 Message::set_interface(Interface *iface)
357 {
358  _transmit_via_iface = iface;
359  _sender_id = iface->serial();
360  recipient_interface_mem_serial = iface->mem_serial();
361 }
362 
363 
364 /** Get transmitting interface.
365  * @return transmitting interface, or NULL if message has not been enqueued, yet.
366  */
367 Interface *
369 {
370  return _transmit_via_iface;
371 }
372 
373 
374 /** Get message type.
375  * @return textual representation of the interface type
376  */
377 const char *
379 {
380  return _type;
381 }
382 
383 
384 /** Get iterator over all fields of this interface instance.
385  * @return field iterator pointing to the very first value
386  */
389 {
390  return InterfaceFieldIterator(_transmit_via_iface, __fieldinfo_list);
391 }
392 
393 
394 /** Invalid iterator.
395  * @return invalid iterator reprensenting the end.
396  */
399 {
400  return InterfaceFieldIterator();
401 }
402 
403 
404 /** Get the number of fields in the message.
405  * @return the number of fields
406  */
407 unsigned int
409 {
410  return __num_fields;
411 }
412 
413 
414 /** Clone this message.
415  * Shall be implemented by every sub-class to return a message of proper type.
416  * @return new message cloned from this instance
417  */
418 Message *
420 {
421  return new Message(this);
422 }
423 
424 /** Add an entry to the info list.
425  * Never use directly, use the interface generator instead. The info list
426  * is used for introspection purposes to allow for iterating over all fields
427  * of an interface.
428  * @param type field type
429  * @param name name of the field, this is referenced, not copied
430  * @param length length of the field
431  * @param value pointer to the value in the data struct
432  * @param enumtype in case the type parameter is enum the name of the enum type
433  * @param enum_map enum value map
434  */
435 void
437  size_t length, void *value, const char *enumtype,
438  const interface_enum_map_t *enum_map)
439 {
440  interface_fieldinfo_t *infol = __fieldinfo_list;
442 
443  newinfo->type = type;
444  newinfo->enumtype = enumtype;
445  newinfo->name = name;
446  newinfo->length = length;
447  newinfo->value = value;
448  newinfo->enum_map = enum_map;
449  newinfo->next = NULL;
450 
451  if ( infol == NULL ) {
452  // first entry
453  __fieldinfo_list = newinfo;
454  } else {
455  // append to list
456  while ( infol->next != NULL ) {
457  infol = infol->next;
458  }
459  infol->next = newinfo;
460  }
461 
462  ++__num_fields;
463 }
464 
465 
466 } // end namespace fawkes
Interface field iterator.
const char * sender_thread_name() const
Get sender of message.
Definition: message.cpp:335
const Time * time_enqueued() const
Get time when message was enqueued.
Definition: message.cpp:265
void * data_ptr
Pointer to memory that contains local data.
Definition: message.h:124
Interface * interface() const
Get transmitting interface.
Definition: message.cpp:368
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
unsigned int id() const
Get message ID.
Definition: message.cpp:197
void mark_enqueued()
Mark message as being enqueued.
Definition: message.cpp:235
void get_timestamp(long &sec, long &usec) const
Get time stamp.
Definition: time.h:114
Interface field info list.
Definition: types.h:56
Fawkes library namespace.
const char * name
Name of this field.
Definition: types.h:59
Timestamp data, must be present and first entries for each interface data structs! This leans on time...
Definition: message.h:129
interface_fieldinfo_t * next
next field, NULL if last
Definition: types.h:63
A class for handling time.
Definition: time.h:91
Thread class encapsulation of pthreads.
Definition: thread.h:42
Base class for all Fawkes BlackBoard interfaces.
Definition: interface.h:79
bool enqueued() const
Check is message has been enqueued.
Definition: message.cpp:251
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: message.cpp:398
static Thread * current_thread_noexc()
Similar to current_thread, but does never throw an exception.
Definition: thread.cpp:1334
const void * datachunk() const
Get pointer to data.
Definition: message.cpp:285
message_data_ts_t * data_ts
data timestamp aliasing pointer
Definition: message.h:133
void * value
Current value of this field.
Definition: types.h:61
unsigned int data_size
Size of memory needed to hold all data.
Definition: message.h:125
unsigned int mem_serial() const
Get memory serial of interface.
Definition: interface.cpp:707
const interface_enum_map_t * enum_map
Map of possible enum values.
Definition: types.h:62
Message(const char *type)
Constructor.
Definition: message.cpp:67
unsigned int sender_id() const
Get ID of sender.
Definition: message.cpp:345
virtual ~Message()
Destructor.
Definition: message.cpp:178
unsigned short serial() const
Get instance serial of interface.
Definition: interface.cpp:697
void set_from_chunk(const void *chunk)
Set from raw data chunk.
Definition: message.cpp:307
unsigned int hops() const
Get number of hops.
Definition: message.cpp:207
interface_fieldtype_t type
type of this field
Definition: types.h:57
int64_t timestamp_usec
additional time microseconds
Definition: message.h:131
const char * name() const
Get name of thread.
Definition: thread.h:95
size_t length
Length of field (array, string)
Definition: types.h:60
unsigned int recipient() const
Get recipient memory serial.
Definition: message.cpp:275
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: message.cpp:388
void set_time(const timeval *tv)
Sets the time.
Definition: time.cpp:262
int64_t timestamp_sec
time in seconds since Unix epoch
Definition: message.h:130
const char * enumtype
text representation of enum type
Definition: types.h:58
unsigned int datasize() const
Get size of data.
Definition: message.cpp:295
unsigned int num_fields() const
Get the number of fields in the message.
Definition: message.cpp:408
Time & stamp()
Set this time to the current time.
Definition: time.cpp:783
void add_fieldinfo(interface_fieldtype_t type, const char *name, size_t length, void *value, const char *enumtype=0, const interface_enum_map_t *enum_map=0)
Add an entry to the info list.
Definition: message.cpp:436
void set_hops(unsigned int hops)
Set number of hops.
Definition: message.cpp:227
interface_fieldtype_t
Interface field type.
Definition: types.h:35
std::map< int, std::string > interface_enum_map_t
Map of enum integer to string values.
Definition: types.h:53
const char * type() const
Get message type.
Definition: message.cpp:378
Message & operator=(const Message &m)
Assign this message to given message.
Definition: message.cpp:320
void set_id(unsigned int message_id)
Set message ID.
Definition: message.cpp:217
virtual Message * clone() const
Clone this message.
Definition: message.cpp:419