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