blob: 7ef7ab1edebad974407f3d752bc566a8059eecb4 [file] [log] [blame]
Brian Silverman2aa83d72015-01-24 18:03:11 -05001#include <memory>
2#include <thread>
3#define __STDC_FORMAT_MACROS
4#include <inttypes.h>
5#include <atomic>
6#include <mutex>
7#include <sched.h>
8#include <assert.h>
9#include <WPILib.h>
10#include "dma.h"
11#include <signal.h>
12
13::std::atomic<double> last_time;
14
15class priority_mutex {
16 public:
17 typedef pthread_mutex_t *native_handle_type;
18
19 // TODO(austin): Write a test case for the mutex, and make the constructor
20 // constexpr.
21 priority_mutex() {
22 pthread_mutexattr_t attr;
23 // Turn on priority inheritance.
24 assert_perror(pthread_mutexattr_init(&attr));
25 assert_perror(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL));
26 assert_perror(pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT));
27
28 assert_perror(pthread_mutex_init(native_handle(), &attr));
29
30 assert_perror(pthread_mutexattr_destroy(&attr));
31 }
32
33 ~priority_mutex() { pthread_mutex_destroy(&handle_); }
34
35 void lock() { assert_perror(pthread_mutex_lock(&handle_)); }
36 bool try_lock() {
37 int ret = pthread_mutex_trylock(&handle_);
38 if (ret == 0) {
39 return true;
40 } else if (ret == EBUSY) {
41 return false;
42 } else {
43 assert_perror(ret);
44 }
45 }
46 void unlock() { assert_perror(pthread_mutex_unlock(&handle_)); }
47
48 native_handle_type native_handle() { return &handle_; }
49
50 private:
51 DISALLOW_COPY_AND_ASSIGN(priority_mutex);
52 pthread_mutex_t handle_;
53};
54
55class EdgePrinter {
56 public:
57 EdgePrinter(DigitalInput *sensor)
58 : quit_(false),
59 sensor_(sensor),
60 interrupt_count_(0) {
61 }
62
63 void Start() {
64 printf("Creating thread %d\n", sensor_->GetChannel());
65 thread_.reset(new ::std::thread(::std::ref(*this)));
66 }
67
68 void operator ()() {
69 struct sched_param param;
70 param.sched_priority = 55;
71 if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
72 perror("sched_setscheduler failed");
73 exit(-1);
74 }
75
76 printf("Started thread %d\n", sensor_->GetChannel());
77
78 sensor_->RequestInterrupts();
79 sensor_->SetUpSourceEdge(true, false);
80
81 InterruptableSensorBase::WaitResult result = InterruptableSensorBase::kBoth;
82 while (!quit_) {
83 result = sensor_->WaitForInterrupt(
84 0.1, result != InterruptableSensorBase::kTimeout);
85 if (result != InterruptableSensorBase::kTimeout) {
86 ++interrupt_count_;
87 printf("Got %d edges on %d\n", interrupt_count_.load(),
88 sensor_->GetChannel());
89 }
90 }
91 }
92
93 int interrupt_count() const { return interrupt_count_; }
94
95 void quit() {
96 quit_ = true;
97 thread_->join();
98 }
99
100 DigitalInput *sensor() { return sensor_.get(); }
101
102 private:
103 ::std::atomic<bool> quit_;
104 ::std::unique_ptr<DigitalInput> sensor_;
105 ::std::atomic<int> interrupt_count_;
106 ::std::unique_ptr<::std::thread> thread_;
107};
108
109class TestRobot;
110static TestRobot *my_robot;
111
112class TestRobot : public RobotBase {
113 public:
114 static void HandleSigIntStatic(int signal) { my_robot->HandleSigInt(signal); }
115 void HandleSigInt(int /*signal*/) { quit_ = true; }
116
117 ::std::unique_ptr<Encoder> MakeEncoder(int index) {
118 return ::std::unique_ptr<Encoder>(
119 new Encoder(sensor(10 + 2 * index), sensor(11 + 2 * index)));
120 }
121
122 ::std::vector<::std::unique_ptr<EdgePrinter>> printers;
123 ::std::vector<::std::unique_ptr<DigitalInput>> dio;
124
125 DigitalInput *sensor(int i) {
126 if (i < 8) {
127 return printers[i]->sensor();
128 } else {
129 return dio[i - 8].get();
130 }
131 }
132
133 void AllEdgeTests() {
134 my_robot = this;
135 quit_ = false;
136 struct sigaction sa;
137
138 memset(&sa, 0, sizeof(sa));
139 // Setup the sighub handler
140 sa.sa_handler = &TestRobot::HandleSigIntStatic;
141
142 // Restart the system call, if at all possible
143 sa.sa_flags = SA_RESTART;
144
145 // Block every signal during the handler
146 sigfillset(&sa.sa_mask);
147
148 for (int i = 0; i < 8; ++i) {
149 printers.emplace_back(new EdgePrinter(new DigitalInput(i)));
150 }
151 printf("Created all objects\n");
152 for (auto &printer : printers) {
153 printer->Start();
154 }
155
156 for (int i = 8; i < 26; ++i) {
157 dio.emplace_back(new DigitalInput(i));
158 }
159
160 ::std::unique_ptr<Encoder> e0 = MakeEncoder(0);
161 ::std::unique_ptr<Encoder> e1 = MakeEncoder(1);
162 ::std::unique_ptr<Encoder> e2 = MakeEncoder(2);
163 ::std::unique_ptr<Encoder> e3 = MakeEncoder(3);
164
165 DMA dma;
166
167 dma.Add(sensor(6));
168 dma.Add(e0.get());
169 dma.SetExternalTrigger(sensor(6), true, true);
170 dma.Start();
171 while (!quit_) {
172 printf("Battery voltage %f\n",
173 DriverStation::GetInstance()->GetBatteryVoltage());
174
175 DMASample dma_sample;
176 size_t left;
177 DMA::ReadStatus dma_read_return = dma.Read(&dma_sample, 1000, &left);
178 printf("dma_read %d, items left %d\n", dma_read_return, left);
179
180 if (left >= 0) {
181 uint32_t sensor_value = 0;
182 uint32_t dma_sensor_value = 0;
183 for (int i = 0; i < 26; ++i) {
184 int j = i;
185 if (j >= 10) j += 6;
186 sensor_value |= (static_cast<uint32_t>(sensor(i)->Get()) << j);
187 dma_sensor_value |= (static_cast<uint32_t>(dma_sample.Get(sensor(i)) << j));
188 }
189
190 printf("dio 0x%x\n", sensor_value);
191 printf("dma 0x%x\n", dma_sensor_value);
192 printf("e0 %d, e0_dma %d\n", e0->GetRaw(), dma_sample.GetRaw(e0.get()));
193 printf("e1 %d, e1_dma %d\n", e1->GetRaw(), dma_sample.GetRaw(e1.get()));
194 printf("e2 %d, e2_dma %d\n", e2->GetRaw(), dma_sample.GetRaw(e2.get()));
195 printf("e3 %d, e3_dma %d\n", e3->GetRaw(), dma_sample.GetRaw(e3.get()));
196 printf("timestamp %f %f\n", dma_sample.GetTimestamp(),
197 static_cast<double>(GetFPGATime()) * 0.000001);
198
199 printf("Remaining is %d\n", left);
200 }
201 }
202 // Wait(0.5);
203 for (auto &printer : printers) {
204 printer->quit();
205 }
206 }
207
208 virtual void StartCompetition() {
209 AllEdgeTests();
210 }
211
212 private:
213 ::std::unique_ptr<Encoder> encoder_;
214 ::std::unique_ptr<Encoder> test_encoder_;
215 ::std::unique_ptr<Talon> talon_;
216 ::std::unique_ptr<DigitalInput> hall_;
217
218 ::std::atomic<bool> quit_;
219 ::std::mutex encoder_mutex_;
220};
221
222START_ROBOT_CLASS(TestRobot);