blob: e87d5e3d9451e6281d2b435e84cc40cdac1bdf33 [file] [log] [blame]
Brian Silvermanf91524f2017-09-23 13:15:55 -04001// This file has the main for the Teensy in the driver's station that
2// communicates over CAN with the one in the pistol grip controller.
3
4#include <stdio.h>
Brian Silvermand930f282017-11-04 23:09:12 -04005#include <atomic>
Brian Silvermanf91524f2017-09-23 13:15:55 -04006
7#include "motors/core/time.h"
8#include "motors/core/kinetis.h"
Brian Silverman4aa83042018-01-05 12:47:31 -08009#include "motors/peripheral/can.h"
Brian Silvermanf91524f2017-09-23 13:15:55 -040010#include "motors/usb/usb.h"
Brian Silvermaneda63f32017-10-08 18:57:33 -040011#include "motors/usb/cdc.h"
Brian Silvermand930f282017-11-04 23:09:12 -040012#include "motors/usb/hid.h"
Brian Silverman4aa83042018-01-05 12:47:31 -080013#include "motors/usb/interrupt_out.h"
Brian Silvermanf91524f2017-09-23 13:15:55 -040014#include "motors/util.h"
15
16namespace frc971 {
17namespace motors {
Brian Silvermaneda63f32017-10-08 18:57:33 -040018namespace {
19
Brian Silvermand930f282017-11-04 23:09:12 -040020::std::atomic<teensy::AcmTty *> global_stdout{nullptr};
21
Brian Silverman6c8b88b2018-09-03 18:17:02 -070022// TODO(Brian): Move this and the other two test functions somewhere else.
23__attribute__((unused)) void EchoChunks(teensy::AcmTty *tty1) {
Brian Silvermaneda63f32017-10-08 18:57:33 -040024 while (true) {
25 char buffer[512];
26 size_t buffered = 0;
27 while (buffered < sizeof(buffer)) {
28 const size_t chunk =
29 tty1->Read(&buffer[buffered], sizeof(buffer) - buffered);
30 buffered += chunk;
31 }
32 size_t written = 0;
33 while (written < buffered) {
34 const size_t chunk = tty1->Write(&buffer[written], buffered - written);
35 written += chunk;
36 }
37
38 GPIOC_PTOR = 1 << 5;
39 for (int i = 0; i < 100000000; ++i) {
40 GPIOC_PSOR = 0;
41 }
42 GPIOC_PTOR = 1 << 5;
43 }
44}
45
Brian Silverman6c8b88b2018-09-03 18:17:02 -070046__attribute__((unused)) void EchoImmediately(teensy::AcmTty *tty1) {
Brian Silvermaneda63f32017-10-08 18:57:33 -040047 while (true) {
48 if (false) {
49 // Delay for a while.
50 for (int i = 0; i < 100000000; ++i) {
51 GPIOC_PSOR = 0;
52 }
53 }
54
55 char buffer[64];
56 const size_t chunk = tty1->Read(buffer, sizeof(buffer));
57 size_t written = 0;
58 while (written < chunk) {
59 written += tty1->Write(&buffer[written], chunk - written);
60 }
61 }
62}
63
Brian Silverman6c8b88b2018-09-03 18:17:02 -070064__attribute__((unused)) void WriteData(teensy::AcmTty *tty1) {
Brian Silvermaneda63f32017-10-08 18:57:33 -040065 GPIOC_PTOR = 1 << 5;
66 for (int i = 0; i < 100000000; ++i) {
67 GPIOC_PSOR = 0;
68 }
69 GPIOC_PTOR = 1 << 5;
70 for (int i = 0; i < 100000000; ++i) {
71 GPIOC_PSOR = 0;
72 }
73
74 const char data[] =
75 "Running command lineRunning command lineRunning command lineRunning "
76 "command lineRunning command lineRunning command lineRunning command "
77 "lineRunning command lineRunning command lineRunning command lineRunning "
78 "command lineRunning command lineRunning command lineRunning command "
79 "lineRunning command lineRunning command lineRunning command lineRunning "
80 "command lineRunning command lineRunning command lineRunning command "
81 "lineRunning command lineRunning command lineRunning command lineRunning "
82 "command lineRunning command lineRunning command lineRunning command "
83 "lineRunning command lineRunning command lineRunning command lineRunning "
84 "command lineRunning command lineRunning command lineRunning command "
85 "lineRunning command lineRunning command lineRunning command lineRunning "
86 "command lineRunning command lineRunning command lineRunning command "
87 "lineRunning command lineRunning command lineRunning command lineRunning "
88 "command lineRunning command lineRunning command lineRunning command "
89 "lineRunning command lineRunning command lineRunning command lineRunning "
90 "command lineRunning command lineRunning command lineRunning command "
91 "lineRunning command lineRunning command lineRunning command lineRunning "
92 "command lineRunning command lineRunning command lineRunning command "
93 "lineRunning command line\n";
94 size_t written = 0;
95 while (written < sizeof(data)) {
96 written += tty1->Write(&data[written], sizeof(data) - written);
97 }
98 GPIOC_PSOR = 1 << 5;
99 while (true) {
100 }
101}
102
Brian Silverman7c7170e2018-01-13 17:41:21 -0800103void ForwardJoystickData(teensy::HidFunction *throttle_joystick,
104 teensy::HidFunction *wheel_joystick,
105 teensy::InterruptOut *interrupt_out) {
Brian Silverman4aa83042018-01-05 12:47:31 -0800106 uint32_t last_command_time = micros();
Brian Silverman7c7170e2018-01-13 17:41:21 -0800107 uint16_t trigger_position = 0x8000;
108 uint16_t wheel_position = 0x8000;
109 uint16_t trigger_velocity = 0x8000;
110 uint16_t wheel_velocity = 0x8000;
111 uint16_t trigger_torque = 0x8000;
112 uint16_t wheel_torque = 0x8000;
113 uint16_t buttons = 0x0080;
Brian Silverman4aa83042018-01-05 12:47:31 -0800114 while (true) {
Brian Silverman7c7170e2018-01-13 17:41:21 -0800115 bool update_report = false;
116
117 uint8_t can_data[8];
Brian Silverman4aa83042018-01-05 12:47:31 -0800118 int length;
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700119 can_receive(can_data, &length, 0);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800120 if (length == 8) {
Brian Silverman4aa83042018-01-05 12:47:31 -0800121 last_command_time = micros();
Brian Silverman7c7170e2018-01-13 17:41:21 -0800122 trigger_position =
123 static_cast<uint16_t>(static_cast<uint32_t>(can_data[0]) |
124 (static_cast<uint32_t>(can_data[1]) << 8));
125 trigger_velocity =
126 static_cast<uint16_t>(static_cast<uint32_t>(can_data[2]) |
127 (static_cast<uint32_t>(can_data[3]) << 8));
128 trigger_torque =
129 static_cast<uint16_t>(static_cast<uint32_t>(can_data[4]) |
130 (static_cast<uint32_t>(can_data[5]) << 8));
131
132 buttons = static_cast<uint16_t>(
133 (buttons & 0xc) | (static_cast<uint32_t>(can_data[7] & 0xc0) >> 6));
134 update_report = true;
135 }
136
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700137 can_receive(can_data, &length, 1);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800138 if (length == 8) {
139 last_command_time = micros();
140 wheel_position =
141 static_cast<uint16_t>(static_cast<uint32_t>(can_data[0]) |
142 (static_cast<uint32_t>(can_data[1]) << 8));
143 wheel_velocity =
144 static_cast<uint16_t>(static_cast<uint32_t>(can_data[2]) |
145 (static_cast<uint32_t>(can_data[3]) << 8));
146 wheel_torque =
147 static_cast<uint16_t>(static_cast<uint32_t>(can_data[4]) |
148 (static_cast<uint32_t>(can_data[5]) << 8));
149
150 buttons = static_cast<uint16_t>(
151 (buttons & 0x3) | (static_cast<uint32_t>(can_data[7] & 0xc0) >> 4));
152 update_report = true;
Brian Silverman4aa83042018-01-05 12:47:31 -0800153 }
154
155 static constexpr uint32_t kTimeout = 10000;
156 if (!time_after(time_add(last_command_time, kTimeout), micros())) {
Brian Silverman7c7170e2018-01-13 17:41:21 -0800157 trigger_position = 0x8000;
158 wheel_position = 0x8000;
159 trigger_velocity = 0x8000;
160 wheel_velocity = 0x8000;
161 trigger_torque = 0x8000;
162 wheel_torque = 0x8000;
163 buttons = 0x0080;
164 update_report = true;
Brian Silverman4aa83042018-01-05 12:47:31 -0800165 // Avoid wrapping back into the valid range.
166 last_command_time = time_subtract(micros(), kTimeout);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800167 }
168
169 if (update_report) {
Brian Silverman4aa83042018-01-05 12:47:31 -0800170 DisableInterrupts disable_interrupts;
Brian Silverman7c7170e2018-01-13 17:41:21 -0800171
172 const uint16_t trigger_packet[] = {
173 trigger_position,
174 trigger_velocity,
175 trigger_torque,
176 static_cast<uint16_t>((trigger_position & 0xff) << 8),
177 static_cast<uint16_t>((trigger_velocity & 0xff) << 8),
178 static_cast<uint16_t>((trigger_torque & 0xff) << 8),
179 buttons};
180 throttle_joystick->UpdateReport(trigger_packet, 14, disable_interrupts);
181
182 const uint16_t wheel_packet[] = {
183 wheel_position,
184 wheel_velocity,
185 wheel_torque,
186 static_cast<uint16_t>((wheel_position & 0xff) << 8),
187 static_cast<uint16_t>((wheel_velocity & 0xff) << 8),
188 static_cast<uint16_t>((wheel_torque & 0xff) << 8),
189 buttons};
190 wheel_joystick->UpdateReport(wheel_packet, 14, disable_interrupts);
191 }
192
193 char usb_out_data[teensy::InterruptOut::kSize];
194 const int usb_out_size = interrupt_out->ReceiveData(usb_out_data);
195 if (usb_out_size >= 16) {
196 can_send(0x2, reinterpret_cast<unsigned char *>(usb_out_data), 8, 2);
197 can_send(0x3, reinterpret_cast<unsigned char *>(usb_out_data) + 8, 8, 3);
Brian Silverman4aa83042018-01-05 12:47:31 -0800198 }
199 }
200}
201
Brian Silverman587edcc2018-01-15 12:00:22 -0800202// The HID report descriptor we use.
203constexpr char kReportDescriptor[] = {
204 0x05, 0x01, // Usage Page (Generic Desktop),
205 0x09, 0x04, // Usage (Joystick),
206 0xA1, 0x01, // Collection (Application),
207 0x75, 0x10, // Report Size (16),
208 0x95, 0x06, // Report Count (6),
209 0x15, 0x00, // Logical Minimum (0),
210 0x26, 0xFF, 0xFF, // Logical Maximum (65535),
211 0x35, 0x00, // Physical Minimum (0),
212 0x46, 0xFF, 0xFF, // Physical Maximum (65535),
213 0x09, 0x30, // Usage (X),
214 0x09, 0x31, // Usage (Y),
215 0x09, 0x32, // Usage (Z),
216 0x09, 0x33, // Usage (Rz),
217 0x09, 0x34, // Usage (?),
218 0x09, 0x35, // Usage (?),
219 0x81, 0x02, // Input (Variable),
220 0x75, 0x01, // Report Size (1),
221 0x95, 0x10, // Report Count (16),
222 0x25, 0x01, // Logical Maximum (1),
223 0x45, 0x01, // Physical Maximum (1),
224 0x05, 0x09, // Usage Page (Button),
225 0x19, 0x01, // Usage Minimum (01),
226 0x29, 0x10, // Usage Maximum (16),
227 0x81, 0x02, // Input (Variable),
228 0xC0 // End Collection
229};
230
Brian Silvermaneda63f32017-10-08 18:57:33 -0400231} // namespace
Brian Silvermanf91524f2017-09-23 13:15:55 -0400232
233extern "C" {
Brian Silvermand930f282017-11-04 23:09:12 -0400234
Brian Silvermanf91524f2017-09-23 13:15:55 -0400235void *__stack_chk_guard = (void *)0x67111971;
Brian Silvermand930f282017-11-04 23:09:12 -0400236
237int _write(int /*file*/, char *ptr, int len) {
238 teensy::AcmTty *const tty = global_stdout.load(::std::memory_order_acquire);
239 if (tty != nullptr) {
240 return tty->Write(ptr, len);
241 }
242 return 0;
Brian Silvermanf91524f2017-09-23 13:15:55 -0400243}
Brian Silvermand930f282017-11-04 23:09:12 -0400244
Brian Silvermanf91524f2017-09-23 13:15:55 -0400245void __stack_chk_fail(void);
246
Brian Silverman19ea60f2018-01-03 21:43:15 -0800247} // extern "C"
248
Brian Silvermanf91524f2017-09-23 13:15:55 -0400249extern "C" int main(void) {
250 // for background about this startup delay, please see these conversations
251 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
252 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
253 delay(400);
254
255 // Set all interrupts to the second-lowest priority to start with.
256 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
257
258 // Now set priorities for all the ones we care about. They only have meaning
259 // relative to each other, which means centralizing them here makes it a lot
260 // more manageable.
261 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
262
263 // Set the LED's pin to output mode.
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500264 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
Brian Silvermanf91524f2017-09-23 13:15:55 -0400265 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
266
Brian Silverman4aa83042018-01-05 12:47:31 -0800267 // Set up the CAN pins.
268 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
269 PORTA_PCR13 = PORT_PCR_DSE | PORT_PCR_MUX(2);
270
Brian Silvermanf91524f2017-09-23 13:15:55 -0400271 delay(100);
272
Brian Silverman4aa83042018-01-05 12:47:31 -0800273 teensy::UsbDevice usb_device(0, 0x16c0, 0x0491);
Brian Silvermaneda63f32017-10-08 18:57:33 -0400274 usb_device.SetManufacturer("FRC 971 Spartan Robotics");
275 usb_device.SetProduct("Pistol Grip Controller interface");
Austin Schuhab15c4d2018-03-09 21:21:03 -0800276
Brian Silverman7c7170e2018-01-13 17:41:21 -0800277 teensy::HidFunction throttle_joystick(&usb_device, 14);
Brian Silverman587edcc2018-01-15 12:00:22 -0800278 throttle_joystick.set_report_descriptor(
279 ::std::string(kReportDescriptor, sizeof(kReportDescriptor)));
Austin Schuhab15c4d2018-03-09 21:21:03 -0800280
Brian Silverman7c7170e2018-01-13 17:41:21 -0800281 teensy::HidFunction wheel_joystick(&usb_device, 14);
Brian Silverman587edcc2018-01-15 12:00:22 -0800282 wheel_joystick.set_report_descriptor(
283 ::std::string(kReportDescriptor, sizeof(kReportDescriptor)));
Austin Schuhab15c4d2018-03-09 21:21:03 -0800284
Brian Silvermaneda63f32017-10-08 18:57:33 -0400285 teensy::AcmTty tty1(&usb_device);
Brian Silvermand930f282017-11-04 23:09:12 -0400286 teensy::AcmTty tty2(&usb_device);
Brian Silverman4aa83042018-01-05 12:47:31 -0800287 teensy::InterruptOut interrupt_out(&usb_device, "JoystickForce");
Brian Silvermand930f282017-11-04 23:09:12 -0400288 global_stdout.store(&tty2, ::std::memory_order_release);
Brian Silvermanf91524f2017-09-23 13:15:55 -0400289 usb_device.Initialize();
290
Brian Silverman7c7170e2018-01-13 17:41:21 -0800291 can_init(0, 1);
Brian Silverman4aa83042018-01-05 12:47:31 -0800292
Brian Silverman7c7170e2018-01-13 17:41:21 -0800293 ForwardJoystickData(&throttle_joystick, &wheel_joystick, &interrupt_out);
Brian Silvermanf91524f2017-09-23 13:15:55 -0400294
295 return 0;
296}
297
298void __stack_chk_fail(void) {
299 while (true) {
300 GPIOC_PSOR = (1 << 5);
301 printf("Stack corruption detected\n");
302 delay(1000);
303 GPIOC_PCOR = (1 << 5);
304 delay(1000);
305 }
306}
307
308} // namespace motors
309} // namespace frc971