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