blob: 85d610e22272378a100076483f28455c16568e49 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_CONTROLS_CONTROL_LOOP_TEST_H_
2#define AOS_CONTROLS_CONTROL_LOOP_TEST_H_
Brian Silverman65e49702014-04-30 17:36:40 -07003
Austin Schuh2001aa42018-10-29 22:57:02 -07004#include <chrono>
5
Brian Silverman65e49702014-04-30 17:36:40 -07006#include "gtest/gtest.h"
7
Austin Schuh9fe68f72019-08-10 19:32:03 -07008#include "aos/events/simulated-event-loop.h"
Austin Schuh2001aa42018-10-29 22:57:02 -07009#include "aos/logging/queue_logging.h"
10#include "aos/robot_state/robot_state.q.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050011#include "aos/testing/test_shm.h"
John Park33858a32018-09-28 23:05:48 -070012#include "aos/time/time.h"
Brian Silverman65e49702014-04-30 17:36:40 -070013
14namespace aos {
15namespace testing {
16
17// Handles setting up the environment that all control loops need to actually
18// run.
19// This includes sending the queue messages and Clear()ing the queues when
20// appropriate.
21// It also includes dealing with ::aos::time.
Austin Schuh2001aa42018-10-29 22:57:02 -070022template <typename TestBaseClass>
23class ControlLoopTestTemplated : public TestBaseClass {
Brian Silverman65e49702014-04-30 17:36:40 -070024 public:
Austin Schuh9fe68f72019-08-10 19:32:03 -070025 ControlLoopTestTemplated(::std::chrono::nanoseconds dt = kTimeTick)
26 : dt_(dt), robot_status_event_loop_(MakeEventLoop()) {
Austin Schuhdf6cbb12019-02-02 13:46:52 -080027 robot_state_sender_ =
Austin Schuh9fe68f72019-08-10 19:32:03 -070028 robot_status_event_loop_->MakeSender<::aos::RobotState>(
29 ".aos.robot_state");
Austin Schuhdf6cbb12019-02-02 13:46:52 -080030 joystick_state_sender_ =
Austin Schuh9fe68f72019-08-10 19:32:03 -070031 robot_status_event_loop_->MakeSender<::aos::JoystickState>(
32 ".aos.joystick_state");
Austin Schuh2001aa42018-10-29 22:57:02 -070033
Austin Schuh9fe68f72019-08-10 19:32:03 -070034 // Schedule the robot status send 1 nanosecond before the loop runs.
35 send_robot_state_phased_loop_ = robot_status_event_loop_->AddPhasedLoop(
36 [this](int) { SendRobotState(); }, dt_,
37 dt - ::std::chrono::nanoseconds(1));
Austin Schuh2001aa42018-10-29 22:57:02 -070038
Austin Schuh9fe68f72019-08-10 19:32:03 -070039 send_joystick_state_timer_ =
40 robot_status_event_loop_->AddTimer([this]() { SendJoystickState(); });
41
42 robot_status_event_loop_->OnRun([this]() {
43 send_joystick_state_timer_->Setup(
44 robot_status_event_loop_->monotonic_now(), dt_);
45 });
Austin Schuh2001aa42018-10-29 22:57:02 -070046 }
Austin Schuh9fe68f72019-08-10 19:32:03 -070047 virtual ~ControlLoopTestTemplated() {}
Brian Silverman65e49702014-04-30 17:36:40 -070048
Philipp Schraderf75a8bf2015-02-02 05:30:16 +000049 void set_team_id(uint16_t team_id) { team_id_ = team_id; }
50 uint16_t team_id() const { return team_id_; }
51
Austin Schuh9fe68f72019-08-10 19:32:03 -070052 // Sets the enabled/disabled bit and (potentially) rebroadcasts the robot
53 // state messages.
54 void SetEnabled(bool enabled) {
55 if (enabled_ != enabled) {
56 enabled_ = enabled;
57 SendJoystickState();
58 SendRobotState();
59 send_joystick_state_timer_->Setup(
60 robot_status_event_loop_->monotonic_now(), dt_);
Austin Schuh2001aa42018-10-29 22:57:02 -070061 }
Brian Silvermane6f64ab2015-02-05 17:03:56 -050062 }
Brian Silverman65e49702014-04-30 17:36:40 -070063
Brian Silverman57cad222015-02-14 20:46:41 -050064 // Simulate a reset of the process reading sensors, which tells loops that all
65 // index counts etc will be reset.
66 void SimulateSensorReset() {
67 ++reader_pid_;
68 }
69
Austin Schuhe5f064d2016-03-05 17:43:51 -080070 // Sets the battery voltage in robot_state.
71 void set_battery_voltage(double battery_voltage) {
72 battery_voltage_ = battery_voltage;
73 }
74
Austin Schuh9fe68f72019-08-10 19:32:03 -070075 ::std::unique_ptr<::aos::EventLoop> MakeEventLoop() {
76 return event_loop_factory_.MakeEventLoop();
77 }
78
79 void RunFor(monotonic_clock::duration duration) {
80 event_loop_factory_.RunFor(duration);
81 }
82
83 ::aos::monotonic_clock::time_point monotonic_now() {
84 return event_loop_factory_.monotonic_now();
85 }
86
87 ::std::chrono::nanoseconds dt() const { return dt_; }
88
Brian Silverman65e49702014-04-30 17:36:40 -070089 private:
Austin Schuh9fe68f72019-08-10 19:32:03 -070090 // Sends out all of the required queue messages.
91 void SendJoystickState() {
92 if (monotonic_now() >= kDSPacketTime + last_ds_time_ ||
93 last_enabled_ != enabled_) {
94 auto new_state = joystick_state_sender_.MakeMessage();
95 new_state->fake = true;
96
97 new_state->enabled = enabled_;
98 new_state->autonomous = false;
99 new_state->team_id = team_id_;
100
101 LOG_STRUCT(INFO, "joystick_state", *new_state);
102 new_state.Send();
103
104 last_ds_time_ = monotonic_now();
105 last_enabled_ = enabled_;
106 }
107 }
108
109 bool last_enabled_ = false;
110
111 void SendRobotState() {
112 auto new_state = robot_state_sender_.MakeMessage();
113
114 new_state->reader_pid = reader_pid_;
115 new_state->outputs_enabled = enabled_;
116 new_state->browned_out = false;
117
118 new_state->is_3v3_active = true;
119 new_state->is_5v_active = true;
120 new_state->voltage_3v3 = 3.3;
121 new_state->voltage_5v = 5.0;
122
123 new_state->voltage_roborio_in = battery_voltage_;
124 new_state->voltage_battery = battery_voltage_;
125
126 LOG_STRUCT(INFO, "robot_state", *new_state);
127 new_state.Send();
128 }
129
130 static constexpr ::std::chrono::microseconds kTimeTick{5000};
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800131 static constexpr ::std::chrono::milliseconds kDSPacketTime{20};
Brian Silvermane6f64ab2015-02-05 17:03:56 -0500132
Austin Schuh9fe68f72019-08-10 19:32:03 -0700133 const ::std::chrono::nanoseconds dt_;
134
135 SimulatedEventLoopFactory event_loop_factory_;
136
Philipp Schraderf75a8bf2015-02-02 05:30:16 +0000137 uint16_t team_id_ = 971;
Brian Silverman57cad222015-02-14 20:46:41 -0500138 int32_t reader_pid_ = 1;
Austin Schuhe5f064d2016-03-05 17:43:51 -0800139 double battery_voltage_ = 12.4;
Philipp Schraderf75a8bf2015-02-02 05:30:16 +0000140
Austin Schuh6a6f90c2016-11-25 21:36:42 -0800141 ::aos::monotonic_clock::time_point last_ds_time_ =
Austin Schuh9fe68f72019-08-10 19:32:03 -0700142 ::aos::monotonic_clock::min_time;
Brian Silverman65e49702014-04-30 17:36:40 -0700143
Austin Schuh9fe68f72019-08-10 19:32:03 -0700144 bool enabled_ = false;
Campbell Crowley152c7cf2016-02-14 21:20:50 -0800145
Austin Schuh9fe68f72019-08-10 19:32:03 -0700146 ::std::unique_ptr<::aos::EventLoop> robot_status_event_loop_;
Austin Schuhdf6cbb12019-02-02 13:46:52 -0800147
148 ::aos::Sender<::aos::RobotState> robot_state_sender_;
149 ::aos::Sender<::aos::JoystickState> joystick_state_sender_;
Austin Schuh9fe68f72019-08-10 19:32:03 -0700150
151 ::aos::PhasedLoopHandler *send_robot_state_phased_loop_ = nullptr;
152 ::aos::TimerHandler *send_joystick_state_timer_ = nullptr;
Brian Silverman65e49702014-04-30 17:36:40 -0700153};
154
Austin Schuh2001aa42018-10-29 22:57:02 -0700155typedef ControlLoopTestTemplated<::testing::Test> ControlLoopTest;
156
157template <typename TestBaseClass>
Austin Schuh9fe68f72019-08-10 19:32:03 -0700158constexpr ::std::chrono::microseconds
159 ControlLoopTestTemplated<TestBaseClass>::kTimeTick;
Austin Schuh2001aa42018-10-29 22:57:02 -0700160
161template <typename TestBaseClass>
162constexpr ::std::chrono::milliseconds ControlLoopTestTemplated<TestBaseClass>::kDSPacketTime;
163
Brian Silverman65e49702014-04-30 17:36:40 -0700164} // namespace testing
165} // namespace aos
166
John Park33858a32018-09-28 23:05:48 -0700167#endif // AOS_CONTROLS_CONTROL_LOOP_TEST_H_