blob: 81baa68cf229afaa5f1a71e6d9146bbf231df53a [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
Austin Schuh9fe68f72019-08-10 19:32:03 -070022// pure virtual methods.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070023template <typename T>
Brian Silvermand8f403a2014-12-13 19:12:04 -050024class LoopOutputHandler {
25 public:
Austin Schuhbb227f82015-09-06 15:27:52 -070026 LoopOutputHandler(
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070027 ::aos::EventLoop *event_loop, const ::std::string &name,
28 ::std::chrono::nanoseconds timeout = ::std::chrono::milliseconds(100))
29 : event_loop_(event_loop), timeout_(timeout) {
30 event_loop_->SetRuntimeRealtimePriority(30);
31 // TODO(austin): Name thread.
32 event_loop_->MakeWatcher(name, [this](const T &t) {
33 // Push the watchdog out a bit further.
34 timer_handler_->Setup(event_loop_->monotonic_now() + timeout_);
35 Write(t);
36 });
Brian Silvermand8f403a2014-12-13 19:12:04 -050037
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070038 // TODO(austin): Set name.
39 timer_handler_ = event_loop_->AddTimer([this]() { Stop(); });
Brian Silvermand8f403a2014-12-13 19:12:04 -050040
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070041 event_loop_->OnRun([this, timeout]() {
42 timer_handler_->Setup(event_loop_->monotonic_now() + timeout_);
43 });
44 }
45
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070046 // Note, all subclasses should call Stop.
47 virtual ~LoopOutputHandler() {}
Brian Silvermand8f403a2014-12-13 19:12:04 -050048
49 protected:
Brian Silvermand8f403a2014-12-13 19:12:04 -050050 // Send the output from the appropriate queue to the hardware.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070051 virtual void Write(const T &t) = 0;
Brian Silvermand8f403a2014-12-13 19:12:04 -050052
53 // Stop all outputs. This will be called in a separate thread (if at all).
54 // The subclass implementation should handle any appropriate logging.
55 // This will be called exactly once if Read() blocks for too long and once
56 // after Quit is called.
57 virtual void Stop() = 0;
58
Austin Schuhdf6cbb12019-02-02 13:46:52 -080059 // Returns a pointer to the event loop.
60 ::aos::EventLoop *event_loop() { return event_loop_; }
61
Brian Silvermand8f403a2014-12-13 19:12:04 -050062 private:
Austin Schuhdf6cbb12019-02-02 13:46:52 -080063 ::aos::EventLoop *event_loop_;
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070064 const ::std::chrono::nanoseconds timeout_;
65 ::aos::TimerHandler *timer_handler_;
Brian Silvermand8f403a2014-12-13 19:12:04 -050066};
67
68} // namespace wpilib
69} // namespace frc971
70
71#endif // FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_