blob: a697339cb705d02d731ad7185c0ece8f4e1c3633 [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
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include "aos/events/event_loop.h"
John Park33858a32018-09-28 23:05:48 -07008#include "aos/scoped/scoped_fd.h"
9#include "aos/time/time.h"
10#include "aos/util/log_interval.h"
Brian Silvermand8f403a2014-12-13 19:12:04 -050011
Brian Silvermand8f403a2014-12-13 19:12:04 -050012namespace frc971 {
13namespace wpilib {
14
15// Handles sending the output from a single control loop to the hardware.
16//
17// This class implements stopping motors when no new values are received for too
18// long efficiently.
19//
20// The intended use is to have a subclass for each loop which implements the
Austin Schuh9fe68f72019-08-10 19:32:03 -070021// pure virtual methods.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070022template <typename T>
Brian Silvermand8f403a2014-12-13 19:12:04 -050023class LoopOutputHandler {
24 public:
Austin Schuhbb227f82015-09-06 15:27:52 -070025 LoopOutputHandler(
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070026 ::aos::EventLoop *event_loop, const ::std::string &name,
27 ::std::chrono::nanoseconds timeout = ::std::chrono::milliseconds(100))
28 : event_loop_(event_loop), timeout_(timeout) {
29 event_loop_->SetRuntimeRealtimePriority(30);
30 // TODO(austin): Name thread.
31 event_loop_->MakeWatcher(name, [this](const T &t) {
32 // Push the watchdog out a bit further.
33 timer_handler_->Setup(event_loop_->monotonic_now() + timeout_);
34 Write(t);
35 });
Brian Silvermand8f403a2014-12-13 19:12:04 -050036
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070037 // TODO(austin): Set name.
38 timer_handler_ = event_loop_->AddTimer([this]() { Stop(); });
Brian Silvermand8f403a2014-12-13 19:12:04 -050039
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070040 event_loop_->OnRun([this, timeout]() {
41 timer_handler_->Setup(event_loop_->monotonic_now() + timeout_);
42 });
43 }
44
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070045 // Note, all subclasses should call Stop.
46 virtual ~LoopOutputHandler() {}
Brian Silvermand8f403a2014-12-13 19:12:04 -050047
48 protected:
Brian Silvermand8f403a2014-12-13 19:12:04 -050049 // Send the output from the appropriate queue to the hardware.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070050 virtual void Write(const T &t) = 0;
Brian Silvermand8f403a2014-12-13 19:12:04 -050051
52 // Stop all outputs. This will be called in a separate thread (if at all).
53 // The subclass implementation should handle any appropriate logging.
54 // This will be called exactly once if Read() blocks for too long and once
55 // after Quit is called.
56 virtual void Stop() = 0;
57
Austin Schuhdf6cbb12019-02-02 13:46:52 -080058 // Returns a pointer to the event loop.
59 ::aos::EventLoop *event_loop() { return event_loop_; }
60
Brian Silvermand8f403a2014-12-13 19:12:04 -050061 private:
Austin Schuhdf6cbb12019-02-02 13:46:52 -080062 ::aos::EventLoop *event_loop_;
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070063 const ::std::chrono::nanoseconds timeout_;
64 ::aos::TimerHandler *timer_handler_;
Brian Silvermand8f403a2014-12-13 19:12:04 -050065};
66
67} // namespace wpilib
68} // namespace frc971
69
70#endif // FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_