blob: 144093d71fbba11261e7a1130544516d0a8e5390 [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
Brian Silvermand8f403a2014-12-13 19:12:04 -05007#include "aos/common/scoped_fd.h"
8#include "aos/common/time.h"
9#include "aos/common/util/log_interval.h"
10
Brian Silvermand8f403a2014-12-13 19:12:04 -050011namespace frc971 {
12namespace wpilib {
13
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
20// pure virtual methods and is then run in a separate thread. The operator()
21// loops writing values until Quit() is called.
22class LoopOutputHandler {
23 public:
Austin Schuhbb227f82015-09-06 15:27:52 -070024 LoopOutputHandler(
25 const ::aos::time::Time &timeout = ::aos::time::Time::InSeconds(0.10));
Brian Silvermand8f403a2014-12-13 19:12:04 -050026
27 void Quit() { run_ = false; }
28
29 void operator()();
30
31 protected:
32 // Read a message from the appropriate queue.
33 // This must block.
34 virtual void Read() = 0;
35
36 // Send the output from the appropriate queue to the hardware.
37 // Read() will always be called at least once before per invocation of this.
38 virtual void Write() = 0;
39
40 // Stop all outputs. This will be called in a separate thread (if at all).
41 // The subclass implementation should handle any appropriate logging.
42 // This will be called exactly once if Read() blocks for too long and once
43 // after Quit is called.
44 virtual void Stop() = 0;
45
46 private:
47 // The thread that actually contains a timerfd to implement timeouts. The
48 // idea is to have a timerfd that is repeatedly set to the timeout expiration
49 // in the future so it will never actually expire unless it is not reset for
50 // too long.
51 //
52 // This class nicely encapsulates the raw fd and manipulating it. Its
53 // operator() loops until Quit() is called, calling Stop() on its associated
54 // LoopOutputHandler whenever the timerfd expires.
55 class Watchdog {
56 public:
Austin Schuhbb227f82015-09-06 15:27:52 -070057 Watchdog(LoopOutputHandler *handler, const ::aos::time::Time &timeout);
Brian Silvermand8f403a2014-12-13 19:12:04 -050058
59 void operator()();
60
61 void Reset();
62
63 void Quit() { run_ = false; }
64
65 private:
66 LoopOutputHandler *const handler_;
67
Austin Schuhbb227f82015-09-06 15:27:52 -070068 const ::aos::time::Time timeout_;
69
Brian Silvermand8f403a2014-12-13 19:12:04 -050070 ::aos::ScopedFD timerfd_;
71
72 ::std::atomic<bool> run_{true};
73 };
74
Brian Silvermand8f403a2014-12-13 19:12:04 -050075 Watchdog watchdog_;
76
77 ::std::atomic<bool> run_{true};
78
Brian Silverman699f0cb2015-02-05 19:45:01 -050079 ::aos::util::SimpleLogInterval no_joystick_state_ =
Austin Schuh61bdc602016-12-04 19:10:10 -080080 ::aos::util::SimpleLogInterval(::std::chrono::milliseconds(500), INFO,
Brian Silverman699f0cb2015-02-05 19:45:01 -050081 "no joystick state -> not outputting");
82 ::aos::util::SimpleLogInterval fake_joystick_state_ =
Austin Schuh61bdc602016-12-04 19:10:10 -080083 ::aos::util::SimpleLogInterval(::std::chrono::milliseconds(500), DEBUG,
Brian Silverman699f0cb2015-02-05 19:45:01 -050084 "fake joystick state -> not outputting");
Brian Silvermand8f403a2014-12-13 19:12:04 -050085};
86
87} // namespace wpilib
88} // namespace frc971
89
90#endif // FRC971_WPILIB_LOOP_OUTPUT_HANDLER_H_