blob: 4b3e04836639939ed033997b2d3bcbf2439ee2da [file] [log] [blame]
Austin Schuh80ff2e12014-03-08 12:06:19 -08001#ifndef FRC971_ACTIONS_ACTION_CLIENT_H_
2#define FRC971_ACTIONS_ACTION_CLIENT_H_
3
4#include <type_traits>
5
6#include "aos/common/logging/logging.h"
7#include "aos/common/queue.h"
8
9namespace frc971 {
10
11class Action {
12 public:
13 // Cancels the action.
14 void Cancel() { DoCancel(); }
15 // Returns true if the action is currently running.
16 bool Running() { return DoRunning(); }
17 // Starts the action.
18 void Start() { DoStart(); }
19
20 // Waits until the action has finished.
21 void WaitUntilDone() { DoWaitUntilDone(); }
22
23 virtual ~Action() {}
24
25 private:
26 virtual void DoCancel() = 0;
27 virtual bool DoRunning() = 0;
28 virtual void DoStart() = 0;
29 virtual void DoWaitUntilDone() = 0;
30};
31
32// Templated subclass to hold the type information.
33template <typename T>
34class TypedAction : public Action {
35 public:
36 typedef typename std::remove_reference<
37 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
38 GoalType;
39
40 TypedAction(T *queue_group)
41 : queue_group_(queue_group),
42 goal_(queue_group_->goal.MakeMessage()),
43 has_started_(false) {}
44
45 // Returns the current goal that will be sent when the action is sent.
46 GoalType *GetGoal() { return goal_.get(); }
47
48 virtual ~TypedAction() {
49 LOG(INFO, "Calling destructor\n");
50 DoCancel();
51 }
52
53 private:
54 // Cancels the action.
55 virtual void DoCancel() {
56 LOG(INFO, "Canceling action on queue %s\n", queue_group_->goal.name());
57 queue_group_->goal.MakeWithBuilder().run(false).Send();
58 }
59
60 // Returns true if the action is running or we don't have an initial response
61 // back from it to signal whether or not it is running.
62 virtual bool DoRunning() {
63 if (has_started_) {
64 queue_group_->status.FetchLatest();
65 } else if (queue_group_->status.FetchLatest()) {
66 if (queue_group_->status->running) {
67 // Wait until it reports that it is running to start.
68 has_started_ = true;
69 }
70 }
71 return !has_started_ ||
72 (queue_group_->status.get() && queue_group_->status->running);
73 }
74
75 // Returns true if the action is running or we don't have an initial response
76 // back from it to signal whether or not it is running.
77 virtual void DoWaitUntilDone() {
78 queue_group_->status.FetchLatest();
79 while (true) {
80 if (has_started_) {
81 queue_group_->status.FetchNextBlocking();
82 } else {
Brian Silverman3c11a0a2014-03-29 16:57:46 -070083 if (queue_group_->status->running) {
84 has_started_ = true;
85 }
Austin Schuh80ff2e12014-03-08 12:06:19 -080086 queue_group_->status.FetchNextBlocking();
87 if (queue_group_->status->running) {
88 // Wait until it reports that it is running to start.
89 has_started_ = true;
90 }
91 }
92 if (has_started_ &&
93 (queue_group_->status.get() && !queue_group_->status->running)) {
94 return;
95 }
96 }
97 }
98
99 // Starts the action if a goal has been created.
100 virtual void DoStart() {
101 if (goal_) {
102 goal_->run = true;
103 goal_.Send();
104 has_started_ = false;
105 LOG(INFO, "Starting action\n");
106 } else {
107 has_started_ = true;
108 }
109 }
110
111 T *queue_group_;
112 ::aos::ScopedMessagePtr<GoalType> goal_;
113 // Track if we have seen a response to the start message.
114 // If we haven't, we are considered running regardless.
115 bool has_started_;
116};
117
118} // namespace frc971
119
120#endif // FRC971_ACTIONS_ACTION_CLIENT_H_