blob: 3c95408d7565f5fa2b055409162986fe5d79be51 [file] [log] [blame]
Brian Silvermand8f403a2014-12-13 19:12:04 -05001#ifndef FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_
2#define FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_
3
Brian Silverman425492b2015-12-30 15:23:55 -08004#include <atomic>
Austin Schuh61bdc602016-12-04 19:10:10 -08005#include <chrono>
Brian Silverman425492b2015-12-30 15:23:55 -08006
Austin Schuhdf6cbb12019-02-02 13:46:52 -08007#include "aos/events/event-loop.h"
8#include "aos/robot_state/robot_state.q.h"
John Park33858a32018-09-28 23:05:48 -07009#include "aos/scoped/scoped_fd.h"
10#include "aos/time/time.h"
11#include "aos/util/log_interval.h"
Brian Silvermand8f403a2014-12-13 19:12:04 -050012
Brian Silvermand8f403a2014-12-13 19:12:04 -050013namespace frc971 {
14namespace wpilib {
15
16// Handles sending the output from a single control loop to the hardware.
17//
18// This class implements stopping motors when no new values are received for too
19// long efficiently.
20//
21// The intended use is to have a subclass for each loop which implements the
22// pure virtual methods and is then run in a separate thread. The operator()
23// loops writing values until Quit() is called.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070024template <typename T>
Brian Silvermand8f403a2014-12-13 19:12:04 -050025class LoopOutputHandler {
26 public:
Austin Schuhbb227f82015-09-06 15:27:52 -070027 LoopOutputHandler(
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070028 ::aos::EventLoop *event_loop, const ::std::string &name,
29 ::std::chrono::nanoseconds timeout = ::std::chrono::milliseconds(100))
30 : event_loop_(event_loop), timeout_(timeout) {
31 event_loop_->SetRuntimeRealtimePriority(30);
32 // TODO(austin): Name thread.
33 event_loop_->MakeWatcher(name, [this](const T &t) {
34 // Push the watchdog out a bit further.
35 timer_handler_->Setup(event_loop_->monotonic_now() + timeout_);
36 Write(t);
37 });
Brian Silvermand8f403a2014-12-13 19:12:04 -050038
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070039 // TODO(austin): Set name.
40 timer_handler_ = event_loop_->AddTimer([this]() { Stop(); });
Brian Silvermand8f403a2014-12-13 19:12:04 -050041
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070042 event_loop_->OnRun([this, timeout]() {
43 timer_handler_->Setup(event_loop_->monotonic_now() + timeout_);
44 });
45 }
46
47 void Quit() { event_loop_->Exit(); }
48
49 // Note, all subclasses should call Stop.
50 virtual ~LoopOutputHandler() {}
Brian Silvermand8f403a2014-12-13 19:12:04 -050051
52 protected:
Brian Silvermand8f403a2014-12-13 19:12:04 -050053 // Send the output from the appropriate queue to the hardware.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070054 virtual void Write(const T &t) = 0;
Brian Silvermand8f403a2014-12-13 19:12:04 -050055
56 // Stop all outputs. This will be called in a separate thread (if at all).
57 // The subclass implementation should handle any appropriate logging.
58 // This will be called exactly once if Read() blocks for too long and once
59 // after Quit is called.
60 virtual void Stop() = 0;
61
Austin Schuhdf6cbb12019-02-02 13:46:52 -080062 // Returns a pointer to the event loop.
63 ::aos::EventLoop *event_loop() { return event_loop_; }
64
Brian Silvermand8f403a2014-12-13 19:12:04 -050065 private:
Austin Schuhdf6cbb12019-02-02 13:46:52 -080066 ::aos::EventLoop *event_loop_;
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070067 const ::std::chrono::nanoseconds timeout_;
68 ::aos::TimerHandler *timer_handler_;
Brian Silvermand8f403a2014-12-13 19:12:04 -050069};
70
71} // namespace wpilib
72} // namespace frc971
73
74#endif // FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_