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