blob: e88b1b760332d50658bcc1f3de1b3fabcdde5845 [file] [log] [blame]
#ifndef AOS_CONTROLS_CONTROL_LOOP_TEST_H_
#define AOS_CONTROLS_CONTROL_LOOP_TEST_H_
#include <chrono>
#include "gtest/gtest.h"
#include "aos/logging/queue_logging.h"
#include "aos/robot_state/robot_state.q.h"
#include "aos/testing/test_shm.h"
#include "aos/time/time.h"
namespace aos {
namespace testing {
// Handles setting up the environment that all control loops need to actually
// run.
// This includes sending the queue messages and Clear()ing the queues when
// appropriate.
// It also includes dealing with ::aos::time.
template <typename TestBaseClass>
class ControlLoopTestTemplated : public TestBaseClass {
public:
ControlLoopTestTemplated() {
::aos::joystick_state.Clear();
::aos::robot_state.Clear();
::aos::time::EnableMockTime(current_time_);
SendMessages(false);
}
virtual ~ControlLoopTestTemplated() {
::aos::joystick_state.Clear();
::aos::robot_state.Clear();
::aos::time::DisableMockTime();
}
void set_team_id(uint16_t team_id) { team_id_ = team_id; }
uint16_t team_id() const { return team_id_; }
// Sends out all of the required queue messages.
void SendMessages(bool enabled) {
if (current_time_ >= kDSPacketTime + last_ds_time_ ||
last_enabled_ != enabled) {
last_ds_time_ = current_time_;
auto new_state = ::aos::joystick_state.MakeMessage();
new_state->fake = true;
new_state->enabled = enabled;
new_state->autonomous = false;
new_state->team_id = team_id_;
new_state.Send();
last_enabled_ = enabled;
}
{
auto new_state = ::aos::robot_state.MakeMessage();
new_state->reader_pid = reader_pid_;
new_state->outputs_enabled = enabled;
new_state->browned_out = false;
new_state->is_3v3_active = true;
new_state->is_5v_active = true;
new_state->voltage_3v3 = 3.3;
new_state->voltage_5v = 5.0;
new_state->voltage_roborio_in = battery_voltage_;
new_state->voltage_battery = battery_voltage_;
LOG_STRUCT(INFO, "robot_state", *new_state);
new_state.Send();
}
}
// Ticks time for a single control loop cycle.
void TickTime(::std::chrono::nanoseconds dt = kTimeTick) {
::aos::time::SetMockTime(current_time_ += dt);
}
// Simulates everything that happens during 1 loop time step.
void SimulateTimestep(bool enabled) {
SendMessages(enabled);
TickTime();
}
// Simulate a reset of the process reading sensors, which tells loops that all
// index counts etc will be reset.
void SimulateSensorReset() {
++reader_pid_;
}
// Sets the battery voltage in robot_state.
void set_battery_voltage(double battery_voltage) {
battery_voltage_ = battery_voltage;
}
private:
static constexpr ::std::chrono::milliseconds kTimeTick{5};
static constexpr ::std::chrono::milliseconds kDSPacketTime{20};
uint16_t team_id_ = 971;
int32_t reader_pid_ = 1;
double battery_voltage_ = 12.4;
::aos::monotonic_clock::time_point last_ds_time_ =
::aos::monotonic_clock::epoch();
::aos::monotonic_clock::time_point current_time_ =
::aos::monotonic_clock::epoch();
::aos::testing::TestSharedMemory my_shm_;
bool last_enabled_ = false;
};
typedef ControlLoopTestTemplated<::testing::Test> ControlLoopTest;
template <typename TestBaseClass>
constexpr ::std::chrono::milliseconds ControlLoopTestTemplated<TestBaseClass>::kTimeTick;
template <typename TestBaseClass>
constexpr ::std::chrono::milliseconds ControlLoopTestTemplated<TestBaseClass>::kDSPacketTime;
} // namespace testing
} // namespace aos
#endif // AOS_CONTROLS_CONTROL_LOOP_TEST_H_