Brian Silverman | 4aa8304 | 2018-01-05 12:47:31 -0800 | [diff] [blame] | 1 | #include "motors/usb/interrupt_out.h" |
| 2 | |
| 3 | namespace frc971 { |
| 4 | namespace teensy { |
| 5 | |
| 6 | void InterruptOut::Initialize() { |
| 7 | interface_ = AddInterface(); |
| 8 | endpoint_ = AddEndpoint(); |
| 9 | |
| 10 | SetMicrosoftDeviceInterfaceGuids("{D4FA286B-C60D-4B99-B49B-9656139F5771}"); |
| 11 | |
| 12 | CreateIadDescriptor( |
| 13 | /*first_interface=*/interface_, |
| 14 | /*interface_count=*/1, |
| 15 | /*function_class=*/vendor_specific_class(), |
| 16 | /*function_subclass=*/0, |
| 17 | /*function_protocol=*/0, name_); |
| 18 | |
| 19 | { |
| 20 | const auto interface_descriptor = CreateDescriptor( |
| 21 | interface_descriptor_length(), UsbDescriptorType::kInterface); |
| 22 | interface_descriptor->AddByte(interface_); // bInterfaceNumber |
| 23 | interface_descriptor->AddByte(0); // bAlternateSetting |
| 24 | interface_descriptor->AddByte(1); // bNumEndpoints |
| 25 | interface_descriptor->AddByte(vendor_specific_class()); // bInterfaceClass |
| 26 | interface_descriptor->AddByte(0x97); // bInterfaceSubClass |
| 27 | interface_descriptor->AddByte(0x97); // bInterfaceProtocol |
| 28 | interface_descriptor->AddByte(device()->AddString(name_)); // iInterface |
| 29 | } |
| 30 | |
| 31 | { |
| 32 | const auto endpoint_descriptor = CreateDescriptor( |
| 33 | endpoint_descriptor_length(), UsbDescriptorType::kEndpoint); |
| 34 | endpoint_descriptor->AddByte(endpoint_); // bEndpointAddress |
| 35 | endpoint_descriptor->AddByte( |
| 36 | m_endpoint_attributes_interrupt()); // bmAttributes |
| 37 | endpoint_descriptor->AddUint16(kSize); // wMaxPacketSize |
| 38 | endpoint_descriptor->AddByte(1); // bInterval |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | void InterruptOut::HandleOutFinished(int endpoint, BdtEntry *bdt_entry) { |
| 43 | if (endpoint == endpoint_) { |
| 44 | |
| 45 | DisableInterrupts disable_interrupts; |
| 46 | if (first_rx_held_ == nullptr) { |
| 47 | first_rx_held_ = bdt_entry; |
| 48 | } else { |
| 49 | second_rx_held_ = bdt_entry; |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | int InterruptOut::ReceiveData(char *buffer) { |
| 55 | DisableInterrupts disable_interrupts; |
| 56 | if (first_rx_held_ == nullptr) { |
| 57 | return -1; |
| 58 | } |
| 59 | |
| 60 | BdtEntry *const bdt_entry = first_rx_held_; |
| 61 | const size_t data_size = G_USB_BD_BC(bdt_entry->buffer_descriptor); |
| 62 | memcpy(buffer, bdt_entry->address, kSize); |
| 63 | dma_memory_barrier(); |
| 64 | |
| 65 | first_rx_held_->buffer_descriptor = M_USB_BD_OWN | M_USB_BD_DTS | |
| 66 | V_USB_BD_BC(kSize) | |
| 67 | static_cast<uint32_t>(next_rx_toggle_); |
| 68 | next_rx_toggle_ = Data01Inverse(next_rx_toggle_); |
| 69 | |
| 70 | first_rx_held_ = second_rx_held_; |
| 71 | second_rx_held_ = nullptr; |
| 72 | return data_size; |
| 73 | } |
| 74 | |
| 75 | void InterruptOut::HandleConfigured(int endpoint) { |
| 76 | if (endpoint == endpoint_) { |
| 77 | device()->ConfigureEndpointFor(endpoint_, true, false, true); |
| 78 | next_rx_toggle_ = Data01::kData0; |
| 79 | device()->SetBdtEntry( |
| 80 | endpoint_, Direction::kRx, EvenOdd::kEven, |
| 81 | {M_USB_BD_OWN | M_USB_BD_DTS | V_USB_BD_BC(buffers_[0].size()), |
| 82 | buffers_[0].data()}); |
| 83 | device()->SetBdtEntry(endpoint_, Direction::kRx, EvenOdd::kOdd, |
| 84 | {M_USB_BD_OWN | M_USB_BD_DTS | |
| 85 | V_USB_BD_BC(buffers_[1].size()) | M_USB_BD_DATA1, |
| 86 | buffers_[1].data()}); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | } // namespace teensy |
| 91 | } // namespace frc971 |