blob: aedaaeafba6b3b90f27e00fb8c9cd01445d5d435 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#ifndef AOS_CRIO_SHARED_LIBS_INTERRUPT_BRIDGE_H_
2#define AOS_CRIO_SHARED_LIBS_INTERRUPT_BRIDGE_H_
3
4#include <wdLib.h>
5#include <semLib.h>
6#include <timers.h>
7#include <signal.h>
8
9#include "aos/common/scoped_ptr.h"
10
Brian Silverman3204dd82013-03-12 18:42:01 -070011#include "aos/common/time.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080012#include "aos/common/macros.h"
brians343bc112013-02-10 01:53:46 +000013
14class Task;
15
16namespace aos {
17namespace crio {
18
19// Handles creating a separate Task at a high priority with a semaphore to
20// link it to something else that provides timing information (likely in an ISR
21// context).
22template<typename T>
23class InterruptBridge {
24 public:
25 // The default priority. Here as a constant for subclasses to use as a default
26 // too.
27 static const int kDefaultPriority = 96;
28 typedef void (*Handler)(T *param);
29
30 // Stops calling the handler at all until a Start function is called again.
31 void Stop();
32
33 protected:
34 // < 95 priority does not work, and < 100 isn't guaranteed to work
35 InterruptBridge(Handler handler, T *param, int priority);
36 // Subclasses should call StopNotifications.
37 virtual ~InterruptBridge();
38
39 // Subclasses should call this whenever the Notifier triggers.
40 // It is safe to call from an ISR.
41 void Notify();
42 // Starts the actual Task.
43 void StartTask();
44
45 private:
46 const Handler handler_;
47 T *const param_;
48
49 // Subclasses should do whatever they have to to stop calling Notify().
50 virtual void StopNotifications() = 0;
51
52 // The function that the Task runs.
53 // Loops forever, waiting for sem_ and then calling handler_.
54 static void HandlerLoop(void *self_in);
55 const scoped_ptr<Task> task_;
56 // For synchronizing between the Task and Notify().
57 SEM_ID sem_;
58 DISALLOW_COPY_AND_ASSIGN(InterruptBridge<T>);
59};
60
61// An accurate version of WPILib's Notifier class.
62template<typename T>
63class PeriodicNotifier : public InterruptBridge<T> {
64 public:
Brian Silverman3204dd82013-03-12 18:42:01 -070065 // Period is how much to wait each time between running the handler.
66 void StartPeriodic(time::Time period);
67 // DEPRECATED(brians): use the overload that takes a time::Time
68 void StartPeriodic(double seconds) {
69 StartPeriodic(time::Time::InSeconds(seconds));
70 }
71 // After StartPeriodic is called, returns whether or not the subclass can
72 // actually call the callback exactly on those intervals or whether it will
73 // call it on some rounded amount.
74 //
75 // Default implementation assumes that the subclass has sysClockRateGet()
76 // resolution. Override if this is not true.
77 virtual bool IsExact() {
78 return period_ == time::Time::InTicks(period_.ToTicks());
79 }
80
81 time::Time period() { return period_; }
brians343bc112013-02-10 01:53:46 +000082
83 protected:
84 PeriodicNotifier(typename InterruptBridge<T>::Handler handler, T *param,
85 int priority);
86 virtual ~PeriodicNotifier() {}
87
88 private:
89 virtual void StopNotifications() = 0;
90 // Subclasses should do whatever they have to to start calling Notify() every
Brian Silverman3204dd82013-03-12 18:42:01 -070091 // period_.
92 virtual void StartNotifications() = 0;
93
94 time::Time period_;
brians343bc112013-02-10 01:53:46 +000095};
96
97// This one works accurately, but it has the potential to drift over time.
98// It has only sysClockRateGet() resolution.
99template<typename T>
100class WDInterruptNotifier : public PeriodicNotifier<T> {
101 public:
102 WDInterruptNotifier(typename InterruptBridge<T>::Handler handler,
103 T *param = NULL,
104 int priority = InterruptBridge<T>::kDefaultPriority);
105 virtual ~WDInterruptNotifier();
106
107 private:
108 // The argument is the general callback parameter which will be a pointer to
109 // an instance. This function calls Notify() on that instance.
110 static void StaticNotify(void *self_in);
111 virtual void StopNotifications();
Brian Silverman3204dd82013-03-12 18:42:01 -0700112 virtual void StartNotifications();
brians343bc112013-02-10 01:53:46 +0000113
114 WDOG_ID wd_;
115 int delay_; // what to pass to wdStart
116 DISALLOW_COPY_AND_ASSIGN(WDInterruptNotifier<T>);
117};
118
119// Vxworks (really really) should take care of making sure that this one
120// doesn't drift over time, but IT DOESN'T!! Brian found the implementation
121// online (file timerLib.c), and it's just doing the same thing as
122// WDInterruptNotifier, except with extra conversions and overhead to implement
123// the POSIX standard. There really is no reason to use this.
124// It has only sysClockRateGet() resolution.
125template<typename T>
126class TimerNotifier : public PeriodicNotifier<T> {
127 public:
128 // unique should be different for all instances created in the same Task. It
129 // can range from 0 to (SIGRTMAX - SIGRTMIN). This instance will use the
130 // signal (SIGRTMIN + unique), so nothing else should use that signal.
131 TimerNotifier(typename InterruptBridge<T>::Handler handler,
132 T *param = NULL,
133 int unique = 0,
134 int priority = InterruptBridge<T>::kDefaultPriority);
135 virtual ~TimerNotifier();
136
137 private:
138 // The first argument is the signal number that is being triggered. This
139 // function looks up a pointer to an instance in timer_notifiers using that
140 // and calls Notify() on that instance.
141 static void StaticNotify(int signum);
142 virtual void StopNotifications();
Brian Silverman3204dd82013-03-12 18:42:01 -0700143 virtual void StartNotifications();
brians343bc112013-02-10 01:53:46 +0000144
145 timer_t timer_;
146 // Which signal timer_ will notify on.
147 const int signal_;
148 // What the action for signal_ was before we started messing with it.
149 struct sigaction old_sa_;
150 DISALLOW_COPY_AND_ASSIGN(TimerNotifier<T>);
151};
152
153} // namespace crio
154} // namespace aos
155
156#include "aos/crio/shared_libs/interrupt_bridge-tmpl.h"
157
158#endif // AOS_CRIO_SHARED_LIBS_INTERRUPT_BRIDGE_H_