blob: 1fb46b2b265b43bd14230780cc4a3f9b2b1895fe [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
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080012namespace frc971::wpilib {
Brian Silvermand8f403a2014-12-13 19:12:04 -050013
14// Handles sending the output from a single control loop to the hardware.
15//
16// This class implements stopping motors when no new values are received for too
17// long efficiently.
18//
19// The intended use is to have a subclass for each loop which implements the
Austin Schuh9fe68f72019-08-10 19:32:03 -070020// pure virtual methods.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070021template <typename T>
Brian Silvermand8f403a2014-12-13 19:12:04 -050022class LoopOutputHandler {
23 public:
Austin Schuhbb227f82015-09-06 15:27:52 -070024 LoopOutputHandler(
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070025 ::aos::EventLoop *event_loop, const ::std::string &name,
26 ::std::chrono::nanoseconds timeout = ::std::chrono::milliseconds(100))
27 : event_loop_(event_loop), timeout_(timeout) {
28 event_loop_->SetRuntimeRealtimePriority(30);
29 // TODO(austin): Name thread.
30 event_loop_->MakeWatcher(name, [this](const T &t) {
31 // Push the watchdog out a bit further.
Philipp Schradera6712522023-07-05 20:25:11 -070032 timer_handler_->Schedule(event_loop_->monotonic_now() + timeout_);
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070033 Write(t);
34 });
Brian Silvermand8f403a2014-12-13 19:12:04 -050035
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070036 // TODO(austin): Set name.
37 timer_handler_ = event_loop_->AddTimer([this]() { Stop(); });
Brian Silvermand8f403a2014-12-13 19:12:04 -050038
James Kuszmaul3ae42262019-11-08 12:33:41 -080039 event_loop_->OnRun([this]() {
Philipp Schradera6712522023-07-05 20:25:11 -070040 timer_handler_->Schedule(event_loop_->monotonic_now() + timeout_);
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070041 });
42 }
43
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070044 // Note, all subclasses should call Stop.
45 virtual ~LoopOutputHandler() {}
Brian Silvermand8f403a2014-12-13 19:12:04 -050046
47 protected:
Brian Silvermand8f403a2014-12-13 19:12:04 -050048 // Send the output from the appropriate queue to the hardware.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070049 virtual void Write(const T &t) = 0;
Brian Silvermand8f403a2014-12-13 19:12:04 -050050
51 // Stop all outputs. This will be called in a separate thread (if at all).
52 // The subclass implementation should handle any appropriate logging.
53 // This will be called exactly once if Read() blocks for too long and once
54 // after Quit is called.
55 virtual void Stop() = 0;
56
Austin Schuhdf6cbb12019-02-02 13:46:52 -080057 // Returns a pointer to the event loop.
58 ::aos::EventLoop *event_loop() { return event_loop_; }
59
Brian Silvermand8f403a2014-12-13 19:12:04 -050060 private:
Austin Schuhdf6cbb12019-02-02 13:46:52 -080061 ::aos::EventLoop *event_loop_;
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070062 const ::std::chrono::nanoseconds timeout_;
63 ::aos::TimerHandler *timer_handler_;
Brian Silvermand8f403a2014-12-13 19:12:04 -050064};
65
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080066} // namespace frc971::wpilib
Brian Silvermand8f403a2014-12-13 19:12:04 -050067
68#endif // FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_