USB Host Shield 2.0
XBOXOLD.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
3  This software may be distributed and modified under the terms of the GNU
4  General Public License version 2 (GPL2) as published by the Free Software
5  Foundation and appearing in the file GPL2.TXT included in the packaging of
6  this file. Please note that GPL2 Section 2[b] requires that all works based
7  on this software must also be made publicly available under the terms of
8  the GPL2 ("Copyleft").
9 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "XBOXOLD.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the Xbox controller
22 
24 const uint8_t XBOXOLD_BUTTONS[] PROGMEM = {
25  0x01, // UP
26  0x08, // RIGHT
27  0x02, // DOWN
28  0x04, // LEFT
29 
30  0x20, // BACK
31  0x10, // START
32  0x40, // L3
33  0x80, // R3
34 
35  // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
36  4, // BLACK
37  5, // WHTIE
38  6, // L1
39  7, // R1
40 
41  1, // B
42  0, // A
43  2, // X
44  3, // Y
45 };
46 
48 pUsb(p), // pointer to USB class instance - mandatory
49 bAddress(0), // device address - mandatory
50 bNumEP(1), // If config descriptor needs to be parsed
51 qNextPollTime(0), // Reset NextPollTime
52 pollInterval(0),
53 bPollEnable(false) { // don't start polling before dongle is connected
54  for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
55  epInfo[i].epAddr = 0;
56  epInfo[i].maxPktSize = (i) ? 0 : 8;
57  epInfo[i].bmSndToggle = 0;
58  epInfo[i].bmRcvToggle = 0;
60  }
61 
62  if(pUsb) // register in USB subsystem
63  pUsb->RegisterDeviceClass(this); //set devConfig[] entry
64 }
65 
66 uint8_t XBOXOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
67  uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
68  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
69  uint8_t rcode;
70  UsbDevice *p = NULL;
71  EpInfo *oldep_ptr = NULL;
72  uint16_t PID;
73  uint16_t VID;
74  uint8_t num_of_conf; // Number of configurations
75 
76  // get memory address of USB device address pool
77  AddressPool &addrPool = pUsb->GetAddressPool();
78 #ifdef EXTRADEBUG
79  Notify(PSTR("\r\nXBOXUSB Init"), 0x80);
80 #endif
81  // check if address has already been assigned to an instance
82  if(bAddress) {
83 #ifdef DEBUG_USB_HOST
84  Notify(PSTR("\r\nAddress in use"), 0x80);
85 #endif
87  }
88 
89  // Get pointer to pseudo device with address 0 assigned
90  p = addrPool.GetUsbDevicePtr(0);
91 
92  if(!p) {
93 #ifdef DEBUG_USB_HOST
94  Notify(PSTR("\r\nAddress not found"), 0x80);
95 #endif
97  }
98 
99  if(!p->epinfo) {
100 #ifdef DEBUG_USB_HOST
101  Notify(PSTR("\r\nepinfo is null"), 0x80);
102 #endif
104  }
105 
106  // Save old pointer to EP_RECORD of address 0
107  oldep_ptr = p->epinfo;
108 
109  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
110  p->epinfo = epInfo;
111 
112  p->lowspeed = lowspeed;
113 
114  // Get device descriptor
115  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
116  // Restore p->epinfo
117  p->epinfo = oldep_ptr;
118 
119  if(rcode)
120  goto FailGetDevDescr;
121 
122  VID = udd->idVendor;
123  PID = udd->idProduct;
124 
125  if(!VIDPIDOK(VID, PID)) // Check if VID and PID match
126  goto FailUnknownDevice;
127 
128  // Allocate new address according to device class
129  bAddress = addrPool.AllocAddress(parent, false, port);
130 
131  if(!bAddress)
133 
134  // Extract Max Packet Size from device descriptor
135  epInfo[0].maxPktSize = udd->bMaxPacketSize0;
136 
137  // Assign new address to the device
138  rcode = pUsb->setAddr(0, 0, bAddress);
139  if(rcode) {
140  p->lowspeed = false;
141  addrPool.FreeAddress(bAddress);
142  bAddress = 0;
143 #ifdef DEBUG_USB_HOST
144  Notify(PSTR("\r\nsetAddr: "), 0x80);
145  D_PrintHex<uint8_t > (rcode, 0x80);
146 #endif
147  return rcode;
148  }
149 #ifdef EXTRADEBUG
150  Notify(PSTR("\r\nAddr: "), 0x80);
151  D_PrintHex<uint8_t > (bAddress, 0x80);
152 #endif
153  //delay(300); // Spec says you should wait at least 200ms
154 
155  p->lowspeed = false;
156 
157  //get pointer to assigned address record
158  p = addrPool.GetUsbDevicePtr(bAddress);
159  if(!p)
161 
162  p->lowspeed = lowspeed;
163 
164  // Assign epInfo to epinfo pointer - only EP0 is known
165  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
166  if(rcode)
167  goto FailSetDevTblEntry;
168 
169  /*
170  We better go and parse configuration values, as there are at least two kind of controllers that use different endpoints,
171  so using hardcoded values cause the usb host to miss all input reports from those controllers.
172 
173  As an example:
174  - 045e:0289 uses EP 1 for IN and EP 2 for OUT
175  - but 045e:0202 uses both EP 2 for IN and OUT
176  */
177  num_of_conf = udd->bNumConfigurations; // Number of configurations
178 
179  USBTRACE2("NC:", num_of_conf);
180 
181  // Check if attached device is a Xbox controller and fill endpoint data structure
182  for(uint8_t i = 0; i < num_of_conf; i++) {
183  ConfigDescParser<0, 0, 0, 0> confDescrParser(this); // Allow all devices, as we have already verified that it is a Xbox controller from the VID and PID
184  rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
185  if(rcode) // Check error code
186  goto FailGetConfDescr;
187  if(bNumEP >= XBOX_MAX_ENDPOINTS) // All endpoints extracted
188  break;
189  }
190 
192  goto FailUnknownDevice;
193 
195  if(rcode)
196  goto FailSetDevTblEntry;
197 
198  delay(200); // Give time for address change
199 
200  rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, bConfNum);
201  if(rcode)
202  goto FailSetConfDescr;
203 
204 #ifdef DEBUG_USB_HOST
205  Notify(PSTR("\r\nXbox Controller Connected\r\n"), 0x80);
206 #endif
207  if(pFuncOnInit)
208  pFuncOnInit(); // Call the user function
209  XboxConnected = true;
210  bPollEnable = true;
211  return 0; // Successful configuration
212 
213  /* Diagnostic messages */
214 FailGetDevDescr:
215 #ifdef DEBUG_USB_HOST
217  goto Fail;
218 #endif
219 
220 FailSetDevTblEntry:
221 #ifdef DEBUG_USB_HOST
223  goto Fail;
224 #endif
225 
226 FailGetConfDescr:
227 #ifdef DEBUG_USB_HOST
229  goto Fail;
230 #endif
231 
232 FailSetConfDescr:
233 #ifdef DEBUG_USB_HOST
235 #endif
236  goto Fail;
237 
238 FailUnknownDevice:
239 #ifdef DEBUG_USB_HOST
240  NotifyFailUnknownDevice(VID, PID);
241 #endif
243 
244 Fail:
245 #ifdef DEBUG_USB_HOST
246  Notify(PSTR("\r\nXbox Init Failed, error code: "), 0x80);
247  NotifyFail(rcode);
248 #endif
249  Release();
250  return rcode;
251 }
252 
253 /* Extracts endpoint information from config descriptor */
254 void XBOXOLD::EndpointXtract(uint8_t conf,
255  uint8_t iface __attribute__((unused)),
256  uint8_t alt __attribute__((unused)),
257  uint8_t proto __attribute__((unused)),
258  const USB_ENDPOINT_DESCRIPTOR *pep)
259 {
260  bConfNum = conf;
261  uint8_t index;
262 
263  if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT) { // Interrupt endpoint
264  index = (pep->bEndpointAddress & 0x80) == 0x80 ? XBOX_INPUT_PIPE : XBOX_OUTPUT_PIPE; // Set the endpoint index
265  } else
266  return;
267 
268  // Fill the rest of endpoint data structure
269  epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
270  epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
271 #ifdef EXTRADEBUG
273 #endif
274  if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
275  pollInterval = pep->bInterval;
276  bNumEP++;
277 }
278 
280  __attribute__((unused)))
281 {
282 #ifdef EXTRADEBUG
283  Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
284  Notify(PSTR("\r\nLength:\t\t"), 0x80);
285  D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
286  Notify(PSTR("\r\nType:\t\t"), 0x80);
287  D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
288  Notify(PSTR("\r\nAddress:\t"), 0x80);
289  D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
290  Notify(PSTR("\r\nAttributes:\t"), 0x80);
291  D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
292  Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
293  D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
294  Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
295  D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
296 #endif
297 }
298 
299 /* Performs a cleanup after failed Init() attempt */
300 uint8_t XBOXOLD::Release() {
301  XboxConnected = false;
303  bAddress = 0;
304  bNumEP = 1; // Must have to be reset to 1
305  qNextPollTime = 0; // Reset next poll time
306  pollInterval = 0;
307  bPollEnable = false;
308 #ifdef DEBUG_USB_HOST
309  Notify(PSTR("\r\nXbox Controller Disconnected\r\n"), 0x80);
310 #endif
311  return 0;
312 }
313 
314 uint8_t XBOXOLD::Poll() {
315  uint8_t rcode = 0;
316 
317  if(!bPollEnable)
318  return 0;
319 
320  if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Do not poll if shorter than polling interval
321  qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time
322  uint16_t length = (uint16_t)epInfo[ XBOX_INPUT_PIPE ].maxPktSize; // Read the maximum packet size from the endpoint
323  uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &length, readBuf, pollInterval);
324  if(!rcode) {
325  readReport();
326 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller
327  printReport(length);
328 #endif
329  }
330 #ifdef DEBUG_USB_HOST
331  else if(rcode != hrNAK) { // Not a matter of no update to send
332  Notify(PSTR("\r\nXbox Poll Failed, error code: "), 0x80);
333  NotifyFail(rcode);
334  }
335 #endif
336  }
337  return rcode;
338 }
339 
340 void XBOXOLD::readReport() {
341  ButtonState = readBuf[2];
342 
343  for(uint8_t i = 0; i < sizeof (buttonValues); i++)
344  buttonValues[i] = readBuf[i + 4]; // A, B, X, Y, BLACK, WHITE, L1, and R1
345 
346  hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
347  hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
348  hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
349  hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[19] << 8) | readBuf[18]);
350 
351  //Notify(PSTR("\r\nButtonState"), 0x80);
352  //PrintHex<uint8_t>(ButtonState, 0x80);
353 
354  if(ButtonState != OldButtonState || memcmp(buttonValues, oldButtonValues, sizeof (buttonValues)) != 0) {
355  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
356  OldButtonState = ButtonState;
357 
358  for(uint8_t i = 0; i < sizeof (buttonValues); i++) {
359  if(oldButtonValues[i] == 0 && buttonValues[i] != 0)
360  buttonClicked[i] = true; // Update A, B, X, Y, BLACK, WHITE, L1, and R1 click state
361  oldButtonValues[i] = buttonValues[i];
362  }
363  }
364 }
365 
366 void XBOXOLD::printReport(uint16_t length __attribute__((unused))) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller
367 #ifdef PRINTREPORT
368  if(readBuf == NULL || !length)
369  return;
370  for(uint8_t i = 0; i < length; i++) {
371  D_PrintHex<uint8_t > (readBuf[i], 0x80);
372  Notify(PSTR(" "), 0x80);
373  }
374  Notify(PSTR("\r\n"), 0x80);
375 #endif
376 }
377 
378 int8_t XBOXOLD::getAnalogIndex(ButtonEnum b) {
379  // For legacy reasons these mapping indices not match up,
380  // as the original code uses L1/R1 for the triggers and
381  // L2/R2 for the white/black buttons. To fix these new enums
382  // we have to transpose the keys before passing them through
383  // the button index function
384  switch (b) {
385  case(LT): b = L1; break; // normally L2
386  case(RT): b = R1; break; // normally R2
387  case(LB): b = WHITE; break; // normally L1
388  case(RB): b = BLACK; break; // normally R1
389  default: break;
390  }
391 
392  // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
393  const int8_t index = ButtonIndex(b);
394 
395  switch (index) {
396  case ButtonIndex(A):
397  case ButtonIndex(B):
398  case ButtonIndex(X):
399  case ButtonIndex(Y):
400  case ButtonIndex(BLACK):
401  case ButtonIndex(WHITE):
402  case ButtonIndex(L1):
403  case ButtonIndex(R1):
404  return index;
405  default: break;
406  }
407 
408  return -1;
409 }
410 
411 int8_t XBOXOLD::getDigitalIndex(ButtonEnum b) {
412  // UP, DOWN, LEFT, RIGHT, START, BACK, L3, and R3 are digital buttons
413  const int8_t index = ButtonIndex(b);
414 
415  switch (index) {
416  case ButtonIndex(UP):
417  case ButtonIndex(DOWN):
418  case ButtonIndex(LEFT):
419  case ButtonIndex(RIGHT):
420  case ButtonIndex(START):
421  case ButtonIndex(BACK):
422  case ButtonIndex(L3):
423  case ButtonIndex(R3):
424  return index;
425  default: break;
426  }
427 
428  return -1;
429 }
430 
432  const int8_t analogIndex = getAnalogIndex(b);
433  if (analogIndex >= 0) {
434  const uint8_t buttonIndex = pgm_read_byte(&XBOXOLD_BUTTONS[analogIndex]);
435  return buttonValues[buttonIndex];
436  }
437  const int8_t digitalIndex = getDigitalIndex(b);
438  if (digitalIndex >= 0) {
439  const uint8_t buttonMask = pgm_read_byte(&XBOXOLD_BUTTONS[digitalIndex]);
440  return (ButtonState & buttonMask);
441  }
442  return 0;
443 }
444 
446  const int8_t analogIndex = getAnalogIndex(b);
447  if (analogIndex >= 0) {
448  const uint8_t buttonIndex = pgm_read_byte(&XBOXOLD_BUTTONS[analogIndex]);
449  if (buttonClicked[buttonIndex]) {
450  buttonClicked[buttonIndex] = false;
451  return true;
452  }
453  return false;
454  }
455  const int8_t digitalIndex = getDigitalIndex(b);
456  if (digitalIndex >= 0) {
457  const uint8_t mask = pgm_read_byte(&XBOXOLD_BUTTONS[digitalIndex]);
458  const bool click = (ButtonClickState & mask);
459  ButtonClickState &= ~mask;
460  return click;
461  }
462  return 0;
463 }
464 
466  return hatValue[a];
467 }
468 
469 /* Xbox Controller commands */
470 void XBOXOLD::XboxCommand(uint8_t* data, uint16_t nbytes) {
471  //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x00), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
472  pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
473 }
474 
475 void XBOXOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) {
476  uint8_t writeBuf[6];
477 
478  writeBuf[0] = 0x00;
479  writeBuf[1] = 0x06;
480  writeBuf[2] = 0x00;
481  writeBuf[3] = rValue; // small weight
482  writeBuf[4] = 0x00;
483  writeBuf[5] = lValue; // big weight
484 
485  XboxCommand(writeBuf, 6);
486 }
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:101
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:106
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition: UsbCore.h:98
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:104
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:103
const uint8_t XBOXOLD_BUTTONS[]
Definition: XBOXOLD.cpp:24
#define XBOX_INPUT_PIPE
Definition: XBOXOLD.h:30
#define XBOX_CONTROL_PIPE
Definition: XBOXOLD.h:29
#define XBOX_OUTPUT_PIPE
Definition: XBOXOLD.h:31
#define XBOX_MAX_ENDPOINTS
Definition: XBOXOLD.h:45
#define USB_NAK_MAX_POWER
Definition: address.h:34
#define USB_NAK_NOWAIT
Definition: address.h:36
virtual void FreeAddress(uint8_t addr)=0
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
Definition: UsbCore.h:218
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:801
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:850
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:841
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:238
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t *dataptr)
Definition: Usb.cpp:806
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p)
Definition: Usb.cpp:126
AddressPool & GetAddressPool()
Definition: UsbCore.h:234
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data, uint8_t bInterval=0)
Definition: Usb.cpp:209
EpInfo epInfo[XBOX_MAX_ENDPOINTS]
Definition: XBOXOLD.h:163
XBOXOLD(USB *pUsb)
Definition: XBOXOLD.cpp:47
USB * pUsb
Definition: XBOXOLD.h:159
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep)
Definition: XBOXOLD.cpp:254
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR *ep_ptr)
Definition: XBOXOLD.cpp:279
uint8_t Poll()
Definition: XBOXOLD.cpp:314
bool getButtonClick(ButtonEnum b)
Definition: XBOXOLD.cpp:445
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid)
Definition: XBOXOLD.h:106
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: XBOXOLD.cpp:66
uint8_t getButtonPress(ButtonEnum b)
Definition: XBOXOLD.cpp:431
uint8_t Release()
Definition: XBOXOLD.cpp:300
uint8_t bConfNum
Definition: XBOXOLD.h:166
bool XboxConnected
Definition: XBOXOLD.h:151
void setRumbleOn(uint8_t lValue, uint8_t rValue)
Definition: XBOXOLD.cpp:475
uint8_t bAddress
Definition: XBOXOLD.h:161
uint32_t qNextPollTime
Definition: XBOXOLD.h:170
uint8_t bNumEP
Definition: XBOXOLD.h:168
int16_t getAnalogHat(AnalogHatEnum a)
Definition: XBOXOLD.cpp:465
constexpr int8_t ButtonIndex(ButtonEnum key)
AnalogHatEnum
@ LeftHatX
@ RightHatY
@ RightHatX
@ LeftHatY
ButtonEnum
@ START
@ WHITE
@ B
@ A
@ LT
@ Y
@ X
@ RB
@ L3
@ DOWN
@ R3
@ UP
@ BACK
@ LEFT
@ L1
@ LB
@ RIGHT
@ L
@ RT
@ BLACK
@ R1
#define USBTRACE2(s, r)
Definition: macros.h:84
#define hrNAK
Definition: max3421e.h:218
#define NotifyFailSetConfDescr(...)
Definition: message.h:60
#define NotifyFailUnknownDevice(...)
Definition: message.h:61
#define NotifyFail(...)
Definition: message.h:62
#define Notify(...)
Definition: message.h:51
#define NotifyFailGetConfDescr(...)
Definition: message.h:59
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:58
#define NotifyFailGetDevDescr(...)
Definition: message.h:57
Definition: address.h:39
uint8_t bmNakPower
Definition: address.h:49
uint8_t bmRcvToggle
Definition: address.h:48
uint8_t epAddr
Definition: address.h:40
uint8_t maxPktSize
Definition: address.h:41
uint8_t bmSndToggle
Definition: address.h:47
uint8_t bEndpointAddress
Definition: usb_ch9.h:151
uint16_t wMaxPacketSize
Definition: usb_ch9.h:153
EpInfo * epinfo
Definition: address.h:83
bool lowspeed
Definition: address.h:86
#define bmUSB_TRANSFER_TYPE
Definition: usb_ch9.h:94
#define USB_TRANSFER_TYPE_INTERRUPT
Definition: usb_ch9.h:93
#define bmREQ_HID_OUT
Definition: usbhid.h:63
#define HID_REQUEST_SET_REPORT
Definition: usbhid.h:72
#define pgm_read_byte(addr)
#define PSTR(str)