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