blob: d78cfd4b4c726cb782c171710932e2f8928d7571 [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 Silvermaneda63f32017-10-08 18:57:33 -040022void EchoChunks(teensy::AcmTty *tty1) {
23 while (true) {
24 char buffer[512];
25 size_t buffered = 0;
26 while (buffered < sizeof(buffer)) {
27 const size_t chunk =
28 tty1->Read(&buffer[buffered], sizeof(buffer) - buffered);
29 buffered += chunk;
30 }
31 size_t written = 0;
32 while (written < buffered) {
33 const size_t chunk = tty1->Write(&buffer[written], buffered - written);
34 written += chunk;
35 }
36
37 GPIOC_PTOR = 1 << 5;
38 for (int i = 0; i < 100000000; ++i) {
39 GPIOC_PSOR = 0;
40 }
41 GPIOC_PTOR = 1 << 5;
42 }
43}
44
45void EchoImmediately(teensy::AcmTty *tty1) {
46 while (true) {
47 if (false) {
48 // Delay for a while.
49 for (int i = 0; i < 100000000; ++i) {
50 GPIOC_PSOR = 0;
51 }
52 }
53
54 char buffer[64];
55 const size_t chunk = tty1->Read(buffer, sizeof(buffer));
56 size_t written = 0;
57 while (written < chunk) {
58 written += tty1->Write(&buffer[written], chunk - written);
59 }
60 }
61}
62
63void WriteData(teensy::AcmTty *tty1) {
64 GPIOC_PTOR = 1 << 5;
65 for (int i = 0; i < 100000000; ++i) {
66 GPIOC_PSOR = 0;
67 }
68 GPIOC_PTOR = 1 << 5;
69 for (int i = 0; i < 100000000; ++i) {
70 GPIOC_PSOR = 0;
71 }
72
73 const char data[] =
74 "Running command lineRunning command lineRunning command lineRunning "
75 "command lineRunning command lineRunning command lineRunning command "
76 "lineRunning command lineRunning command lineRunning command lineRunning "
77 "command lineRunning command lineRunning command lineRunning command "
78 "lineRunning command lineRunning command lineRunning command lineRunning "
79 "command lineRunning command lineRunning command lineRunning command "
80 "lineRunning command lineRunning command lineRunning command lineRunning "
81 "command lineRunning command lineRunning command lineRunning command "
82 "lineRunning command lineRunning command lineRunning command lineRunning "
83 "command lineRunning command lineRunning command lineRunning command "
84 "lineRunning command lineRunning command lineRunning command lineRunning "
85 "command lineRunning command lineRunning command lineRunning command "
86 "lineRunning command lineRunning command lineRunning command lineRunning "
87 "command lineRunning command lineRunning command lineRunning command "
88 "lineRunning command lineRunning command lineRunning command lineRunning "
89 "command lineRunning command lineRunning command lineRunning command "
90 "lineRunning command lineRunning command lineRunning command lineRunning "
91 "command lineRunning command lineRunning command lineRunning command "
92 "lineRunning command line\n";
93 size_t written = 0;
94 while (written < sizeof(data)) {
95 written += tty1->Write(&data[written], sizeof(data) - written);
96 }
97 GPIOC_PSOR = 1 << 5;
98 while (true) {
99 }
100}
101
Brian Silverman7c7170e2018-01-13 17:41:21 -0800102void ForwardJoystickData(teensy::HidFunction *throttle_joystick,
103 teensy::HidFunction *wheel_joystick,
104 teensy::InterruptOut *interrupt_out) {
Brian Silverman4aa83042018-01-05 12:47:31 -0800105 uint32_t last_command_time = micros();
Brian Silverman7c7170e2018-01-13 17:41:21 -0800106 uint16_t trigger_position = 0x8000;
107 uint16_t wheel_position = 0x8000;
108 uint16_t trigger_velocity = 0x8000;
109 uint16_t wheel_velocity = 0x8000;
110 uint16_t trigger_torque = 0x8000;
111 uint16_t wheel_torque = 0x8000;
112 uint16_t buttons = 0x0080;
Brian Silverman4aa83042018-01-05 12:47:31 -0800113 while (true) {
Brian Silverman7c7170e2018-01-13 17:41:21 -0800114 bool update_report = false;
115
116 uint8_t can_data[8];
Brian Silverman4aa83042018-01-05 12:47:31 -0800117 int length;
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700118 can_receive(can_data, &length, 0);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800119 if (length == 8) {
Brian Silverman4aa83042018-01-05 12:47:31 -0800120 last_command_time = micros();
Brian Silverman7c7170e2018-01-13 17:41:21 -0800121 trigger_position =
122 static_cast<uint16_t>(static_cast<uint32_t>(can_data[0]) |
123 (static_cast<uint32_t>(can_data[1]) << 8));
124 trigger_velocity =
125 static_cast<uint16_t>(static_cast<uint32_t>(can_data[2]) |
126 (static_cast<uint32_t>(can_data[3]) << 8));
127 trigger_torque =
128 static_cast<uint16_t>(static_cast<uint32_t>(can_data[4]) |
129 (static_cast<uint32_t>(can_data[5]) << 8));
130
131 buttons = static_cast<uint16_t>(
132 (buttons & 0xc) | (static_cast<uint32_t>(can_data[7] & 0xc0) >> 6));
133 update_report = true;
134 }
135
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700136 can_receive(can_data, &length, 1);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800137 if (length == 8) {
138 last_command_time = micros();
139 wheel_position =
140 static_cast<uint16_t>(static_cast<uint32_t>(can_data[0]) |
141 (static_cast<uint32_t>(can_data[1]) << 8));
142 wheel_velocity =
143 static_cast<uint16_t>(static_cast<uint32_t>(can_data[2]) |
144 (static_cast<uint32_t>(can_data[3]) << 8));
145 wheel_torque =
146 static_cast<uint16_t>(static_cast<uint32_t>(can_data[4]) |
147 (static_cast<uint32_t>(can_data[5]) << 8));
148
149 buttons = static_cast<uint16_t>(
150 (buttons & 0x3) | (static_cast<uint32_t>(can_data[7] & 0xc0) >> 4));
151 update_report = true;
Brian Silverman4aa83042018-01-05 12:47:31 -0800152 }
153
154 static constexpr uint32_t kTimeout = 10000;
155 if (!time_after(time_add(last_command_time, kTimeout), micros())) {
Brian Silverman7c7170e2018-01-13 17:41:21 -0800156 trigger_position = 0x8000;
157 wheel_position = 0x8000;
158 trigger_velocity = 0x8000;
159 wheel_velocity = 0x8000;
160 trigger_torque = 0x8000;
161 wheel_torque = 0x8000;
162 buttons = 0x0080;
163 update_report = true;
Brian Silverman4aa83042018-01-05 12:47:31 -0800164 // Avoid wrapping back into the valid range.
165 last_command_time = time_subtract(micros(), kTimeout);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800166 }
167
168 if (update_report) {
Brian Silverman4aa83042018-01-05 12:47:31 -0800169 DisableInterrupts disable_interrupts;
Brian Silverman7c7170e2018-01-13 17:41:21 -0800170
171 const uint16_t trigger_packet[] = {
172 trigger_position,
173 trigger_velocity,
174 trigger_torque,
175 static_cast<uint16_t>((trigger_position & 0xff) << 8),
176 static_cast<uint16_t>((trigger_velocity & 0xff) << 8),
177 static_cast<uint16_t>((trigger_torque & 0xff) << 8),
178 buttons};
179 throttle_joystick->UpdateReport(trigger_packet, 14, disable_interrupts);
180
181 const uint16_t wheel_packet[] = {
182 wheel_position,
183 wheel_velocity,
184 wheel_torque,
185 static_cast<uint16_t>((wheel_position & 0xff) << 8),
186 static_cast<uint16_t>((wheel_velocity & 0xff) << 8),
187 static_cast<uint16_t>((wheel_torque & 0xff) << 8),
188 buttons};
189 wheel_joystick->UpdateReport(wheel_packet, 14, disable_interrupts);
190 }
191
192 char usb_out_data[teensy::InterruptOut::kSize];
193 const int usb_out_size = interrupt_out->ReceiveData(usb_out_data);
194 if (usb_out_size >= 16) {
195 can_send(0x2, reinterpret_cast<unsigned char *>(usb_out_data), 8, 2);
196 can_send(0x3, reinterpret_cast<unsigned char *>(usb_out_data) + 8, 8, 3);
Brian Silverman4aa83042018-01-05 12:47:31 -0800197 }
198 }
199}
200
Brian Silverman587edcc2018-01-15 12:00:22 -0800201// The HID report descriptor we use.
202constexpr char kReportDescriptor[] = {
203 0x05, 0x01, // Usage Page (Generic Desktop),
204 0x09, 0x04, // Usage (Joystick),
205 0xA1, 0x01, // Collection (Application),
206 0x75, 0x10, // Report Size (16),
207 0x95, 0x06, // Report Count (6),
208 0x15, 0x00, // Logical Minimum (0),
209 0x26, 0xFF, 0xFF, // Logical Maximum (65535),
210 0x35, 0x00, // Physical Minimum (0),
211 0x46, 0xFF, 0xFF, // Physical Maximum (65535),
212 0x09, 0x30, // Usage (X),
213 0x09, 0x31, // Usage (Y),
214 0x09, 0x32, // Usage (Z),
215 0x09, 0x33, // Usage (Rz),
216 0x09, 0x34, // Usage (?),
217 0x09, 0x35, // Usage (?),
218 0x81, 0x02, // Input (Variable),
219 0x75, 0x01, // Report Size (1),
220 0x95, 0x10, // Report Count (16),
221 0x25, 0x01, // Logical Maximum (1),
222 0x45, 0x01, // Physical Maximum (1),
223 0x05, 0x09, // Usage Page (Button),
224 0x19, 0x01, // Usage Minimum (01),
225 0x29, 0x10, // Usage Maximum (16),
226 0x81, 0x02, // Input (Variable),
227 0xC0 // End Collection
228};
229
Brian Silvermaneda63f32017-10-08 18:57:33 -0400230} // namespace
Brian Silvermanf91524f2017-09-23 13:15:55 -0400231
232extern "C" {
Brian Silvermand930f282017-11-04 23:09:12 -0400233
Brian Silvermanf91524f2017-09-23 13:15:55 -0400234void *__stack_chk_guard = (void *)0x67111971;
Brian Silvermand930f282017-11-04 23:09:12 -0400235
236int _write(int /*file*/, char *ptr, int len) {
237 teensy::AcmTty *const tty = global_stdout.load(::std::memory_order_acquire);
238 if (tty != nullptr) {
239 return tty->Write(ptr, len);
240 }
241 return 0;
Brian Silvermanf91524f2017-09-23 13:15:55 -0400242}
Brian Silvermand930f282017-11-04 23:09:12 -0400243
Brian Silvermanf91524f2017-09-23 13:15:55 -0400244void __stack_chk_fail(void);
245
Brian Silverman19ea60f2018-01-03 21:43:15 -0800246} // extern "C"
247
Brian Silvermanf91524f2017-09-23 13:15:55 -0400248extern "C" int main(void) {
249 // for background about this startup delay, please see these conversations
250 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
251 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
252 delay(400);
253
254 // Set all interrupts to the second-lowest priority to start with.
255 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
256
257 // Now set priorities for all the ones we care about. They only have meaning
258 // relative to each other, which means centralizing them here makes it a lot
259 // more manageable.
260 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
261
262 // Set the LED's pin to output mode.
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500263 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
Brian Silvermanf91524f2017-09-23 13:15:55 -0400264 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
265
Brian Silverman4aa83042018-01-05 12:47:31 -0800266 // Set up the CAN pins.
267 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
268 PORTA_PCR13 = PORT_PCR_DSE | PORT_PCR_MUX(2);
269
Brian Silvermanf91524f2017-09-23 13:15:55 -0400270 delay(100);
271
Brian Silverman4aa83042018-01-05 12:47:31 -0800272 teensy::UsbDevice usb_device(0, 0x16c0, 0x0491);
Brian Silvermaneda63f32017-10-08 18:57:33 -0400273 usb_device.SetManufacturer("FRC 971 Spartan Robotics");
274 usb_device.SetProduct("Pistol Grip Controller interface");
Austin Schuhab15c4d2018-03-09 21:21:03 -0800275
Brian Silverman7c7170e2018-01-13 17:41:21 -0800276 teensy::HidFunction throttle_joystick(&usb_device, 14);
Brian Silverman587edcc2018-01-15 12:00:22 -0800277 throttle_joystick.set_report_descriptor(
278 ::std::string(kReportDescriptor, sizeof(kReportDescriptor)));
Austin Schuhab15c4d2018-03-09 21:21:03 -0800279
Brian Silverman7c7170e2018-01-13 17:41:21 -0800280 teensy::HidFunction wheel_joystick(&usb_device, 14);
Brian Silverman587edcc2018-01-15 12:00:22 -0800281 wheel_joystick.set_report_descriptor(
282 ::std::string(kReportDescriptor, sizeof(kReportDescriptor)));
Austin Schuhab15c4d2018-03-09 21:21:03 -0800283
Brian Silvermaneda63f32017-10-08 18:57:33 -0400284 teensy::AcmTty tty1(&usb_device);
Brian Silvermand930f282017-11-04 23:09:12 -0400285 teensy::AcmTty tty2(&usb_device);
Brian Silverman4aa83042018-01-05 12:47:31 -0800286 teensy::InterruptOut interrupt_out(&usb_device, "JoystickForce");
Brian Silvermand930f282017-11-04 23:09:12 -0400287 global_stdout.store(&tty2, ::std::memory_order_release);
Brian Silvermanf91524f2017-09-23 13:15:55 -0400288 usb_device.Initialize();
289
Brian Silverman7c7170e2018-01-13 17:41:21 -0800290 can_init(0, 1);
Brian Silverman4aa83042018-01-05 12:47:31 -0800291
Brian Silverman7c7170e2018-01-13 17:41:21 -0800292 ForwardJoystickData(&throttle_joystick, &wheel_joystick, &interrupt_out);
Brian Silvermanf91524f2017-09-23 13:15:55 -0400293
294 return 0;
295}
296
297void __stack_chk_fail(void) {
298 while (true) {
299 GPIOC_PSOR = (1 << 5);
300 printf("Stack corruption detected\n");
301 delay(1000);
302 GPIOC_PCOR = (1 << 5);
303 delay(1000);
304 }
305}
306
307} // namespace motors
308} // namespace frc971