blob: ff8415fd94d30fece5cca3be648cae4575b048ba [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.
24class LoopOutputHandler {
25 public:
Austin Schuhbb227f82015-09-06 15:27:52 -070026 LoopOutputHandler(
Austin Schuhdf6cbb12019-02-02 13:46:52 -080027 ::aos::EventLoop *event_loop,
Austin Schuhf2a50ba2016-12-24 16:16:26 -080028 ::std::chrono::nanoseconds timeout = ::std::chrono::milliseconds(100));
Brian Silvermand8f403a2014-12-13 19:12:04 -050029
30 void Quit() { run_ = false; }
31
32 void operator()();
33
34 protected:
35 // Read a message from the appropriate queue.
36 // This must block.
37 virtual void Read() = 0;
38
39 // Send the output from the appropriate queue to the hardware.
40 // Read() will always be called at least once before per invocation of this.
41 virtual void Write() = 0;
42
43 // Stop all outputs. This will be called in a separate thread (if at all).
44 // The subclass implementation should handle any appropriate logging.
45 // This will be called exactly once if Read() blocks for too long and once
46 // after Quit is called.
47 virtual void Stop() = 0;
48
Austin Schuhdf6cbb12019-02-02 13:46:52 -080049 // Returns a pointer to the event loop.
50 ::aos::EventLoop *event_loop() { return event_loop_; }
51
Brian Silvermand8f403a2014-12-13 19:12:04 -050052 private:
53 // The thread that actually contains a timerfd to implement timeouts. The
54 // idea is to have a timerfd that is repeatedly set to the timeout expiration
55 // in the future so it will never actually expire unless it is not reset for
56 // too long.
57 //
58 // This class nicely encapsulates the raw fd and manipulating it. Its
59 // operator() loops until Quit() is called, calling Stop() on its associated
60 // LoopOutputHandler whenever the timerfd expires.
61 class Watchdog {
62 public:
Austin Schuhf2a50ba2016-12-24 16:16:26 -080063 Watchdog(LoopOutputHandler *handler, ::std::chrono::nanoseconds timeout);
Brian Silvermand8f403a2014-12-13 19:12:04 -050064
65 void operator()();
66
67 void Reset();
68
69 void Quit() { run_ = false; }
70
71 private:
72 LoopOutputHandler *const handler_;
73
Austin Schuhf2a50ba2016-12-24 16:16:26 -080074 const ::std::chrono::nanoseconds timeout_;
Austin Schuhbb227f82015-09-06 15:27:52 -070075
Brian Silvermand8f403a2014-12-13 19:12:04 -050076 ::aos::ScopedFD timerfd_;
77
78 ::std::atomic<bool> run_{true};
79 };
80
Austin Schuhdf6cbb12019-02-02 13:46:52 -080081 ::aos::EventLoop *event_loop_;
82 ::aos::Fetcher<::aos::JoystickState> joystick_state_fetcher_;
Brian Silvermand8f403a2014-12-13 19:12:04 -050083 Watchdog watchdog_;
84
85 ::std::atomic<bool> run_{true};
86
Brian Silverman699f0cb2015-02-05 19:45:01 -050087 ::aos::util::SimpleLogInterval no_joystick_state_ =
Austin Schuh61bdc602016-12-04 19:10:10 -080088 ::aos::util::SimpleLogInterval(::std::chrono::milliseconds(500), INFO,
Brian Silverman699f0cb2015-02-05 19:45:01 -050089 "no joystick state -> not outputting");
90 ::aos::util::SimpleLogInterval fake_joystick_state_ =
Austin Schuh61bdc602016-12-04 19:10:10 -080091 ::aos::util::SimpleLogInterval(::std::chrono::milliseconds(500), DEBUG,
Brian Silverman699f0cb2015-02-05 19:45:01 -050092 "fake joystick state -> not outputting");
Brian Silvermand8f403a2014-12-13 19:12:04 -050093};
94
95} // namespace wpilib
96} // namespace frc971
97
98#endif // FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_