blob: 2b7c0d7ef8ed519cd523f5a06b1dbe073fd79596 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#ifndef __AOS_MESSAGES_QUEUE_HOLDER_H_
2#define __AOS_MESSAGES_QUEUE_HOLDER_H_
3
4#include <stddef.h>
Brian Silvermanf665d692013-02-17 22:11:39 -08005#include <string.h>
brians343bc112013-02-10 01:53:46 +00006
7#include <algorithm>
8
9#include "aos/aos_core.h"
10#include "aos/common/control_loop/Timing.h"
11#include "aos/common/byteorder.h"
12#include "aos/common/time.h"
13#include "aos/common/type_traits.h"
14
15namespace aos {
16
17// Specializations of TypeOperator and QueueBuilder that are actually
18// implemented are created in the generated code for all message value types.
19// These specializations have the same functions declared in the actual types.
20
21// Defines a way for types to be manipulated.
22template<typename T> class TypeOperator {
23 public:
24 // Sets all fields to their default constructor.
25 static void Zero(T &t_);
26 // Returns the size of buffer NToH and HToN use.
27 static size_t Size();
28 // Converts everything from network to host byte order.
29 // input must have Size() bytes available in it.
30 static void NToH(char *input, T &t_);
31 // Converts everything from host to network byte order and puts it into output.
32 // output must have Size() bytes available in it.
33 static void HToN(const T &t_, char *output);
34 // Creates a string with the names and values of all the fields.
35 // The return value might will be to a static buffer.
36 static const char *Print(const T &t_);
37};
38
39template<typename T> class QueueHolder;
40
41// An easy way to set values for queue messages.
42// Each specialization has chainable setter functions for building a message
43// of type T to put into a queue (like QueueBuilder<T> &field(int value);).
44template<class T> class QueueBuilder {
45 public:
46 QueueBuilder(QueueHolder<T> &holder);
47 bool Send();
48};
49
50// Internal class to make implementing identical behavior with structs that go
51// into queues easier. Also a central location for the documentation.
52//
53// When compiled for the cRIO, everything except Clear does nothing (and Get
54// turns into just a Clear) which means that the internal T instance is the only one.
55// Also, the internal instance becomes static.
56//
57// To look at the current message, you Get a copy and then View the result.
58// To make changes, you modify the message that you can View (after possibly
59// Clearing it) and then you Send it. You can also just Clear the message, put
60// data into it, and then Send it. A way to modify the local message is using
61// the Builder function.
62// Note that there is no way to avoid potentially overwriting other changes between
63// when you Get one and when you Send it (mainly applicable to 1-length queues).
64//
65// T must be POD and have a "timespec set_time;" field.
66//
67// This first class doesn't have the builder; QueueHolder does.
68#define aos_check_rv __attribute__((warn_unused_result))
69template<typename T> class QueueHolderNoBuilder {
70#ifndef __VXWORKS__
71 aos_queue *const queue_;
72 static_assert(shm_ok<T>::value, "T must be able to"
73 " go through shared memory and memcpy");
74 T t_;
75#else
76 static T t_;
77#endif
78 public:
79#ifndef __VXWORKS__
80 explicit QueueHolderNoBuilder(aos_queue *queue) : queue_(queue) {}
81#else
82 QueueHolderNoBuilder() {}
83#endif
84 // Gets the current value and stores it in View().
85 // check_time is whether or not to check to see if the last time a value was Sent
86 // was too long ago (returns false if it was)
87 // Returns true if View() is now the current value.
88 // IMPORTANT: If this function returns false, the contents of View() are
89 // either the same as they were before or (if check_time is true) the current
90 // message. That is why it creates compile-time warnings if the return value
91 // is not checked.
92 bool Get(bool check_time) aos_check_rv;
93 // Looks at the current value. Starts out undefined.
94 // If the last Get call returned false, then this the contents of the
95 // return value are undefined.
96#ifdef __VXWORKS__
97 static
98#endif
99 inline T &View() { return t_; }
100 // Clears (calls the default constructor of) all the fields of the current
101 // Goal.
102 void Clear() { TypeOperator<T>::Zero(t_); }
103 // Sends the current value. Does not affect the current value.
104 // Returns whether or not the Send succeeded.
105 bool Send();
106 // Returns a string containing the values of all the fields in the current
107 // value.
108 // The return value is valid until Print is called again. The class owns the
109 // memory.
110 const char *Print() const { return TypeOperator<T>::Print(t_); }
111};
112
113template<typename T>
114bool QueueHolderNoBuilder<T>::Get(bool check_time) {
115#ifdef __VXWORKS__
116 (void)check_time;
117 return true;
118#else
119 const T *msg = static_cast<const T *>(aos_queue_read_msg(queue_,
120 PEEK | NON_BLOCK));
121 if (msg == NULL) {
122 return false;
123 }
124 static_assert(sizeof(t_) == sizeof(*msg), "something is wrong here");
125 memcpy(&t_, msg, sizeof(t_));
126 aos_queue_free_msg(queue_, msg);
127 if (check_time && !((time::Time::Now() - time::Time(t_.set_time)) > time::Time::InMS(45))) {
128 LOG(WARNING, "too long since last Set msg={%s}\n", Print());
129 return false;
130 } else {
131 return true;
132 }
133#endif
134}
135template<typename T>
136bool QueueHolderNoBuilder<T>::Send() {
137#ifndef __VXWORKS__
138 T *msg = static_cast<T *>(aos_queue_get_msg(queue_));
139 if (msg == NULL) {
140 return false;
141 }
142 static_assert(sizeof(*msg) == sizeof(t_), "something is wrong here");
143 memcpy(msg, &t_, sizeof(t_));
144 msg->set_time = ::aos::time::Time::Now().ToTimespec();
145
146 return aos_queue_write_msg_free(queue_, msg, OVERRIDE) == 0;
147#else
148 return true;
149#endif
150}
151#ifdef __VXWORKS__
152template<typename T> T QueueHolderNoBuilder<T>::t_;
153#endif
154template<typename T> class QueueHolder : public QueueHolderNoBuilder<T> {
155 QueueBuilder<T> builder_;
156 public:
157#ifndef __VXWORKS__
158 explicit QueueHolder(aos_queue *queue) : QueueHolderNoBuilder<T>(queue),
159 builder_(*this) {}
160#else
161 QueueHolder() : builder_(*this) {}
162#endif
163 // Clears the current Goal and returns an object that allows setting various
164 // fields with chained method calls and then calling Send() on it.
165 QueueBuilder<T> &Builder() {
166 QueueHolderNoBuilder<T>::Clear();
167 return builder_;
168 }
169};
170
171} // namespace aos
172
173#endif
174