mirror of
https://github.com/arduino/Arduino.git
synced 2025-03-13 10:29:35 +01:00
[sam] USBHost ADK+HID supported okay. Code is more documented.
This commit is contained in:
parent
96e8db0299
commit
3ba2e37651
@ -1,61 +1,54 @@
|
||||
#include "variant.h"
|
||||
#include <stdio.h>
|
||||
#include <hidboot.h>
|
||||
#include <adk.h>
|
||||
|
||||
class MouseRptParser : public MouseReportParser
|
||||
{
|
||||
protected:
|
||||
virtual void OnMouseMove (MOUSEINFO *mi);
|
||||
virtual void OnLeftButtonUp (MOUSEINFO *mi);
|
||||
virtual void OnLeftButtonDown (MOUSEINFO *mi);
|
||||
virtual void OnRightButtonUp (MOUSEINFO *mi);
|
||||
virtual void OnRightButtonDown (MOUSEINFO *mi);
|
||||
virtual void OnMiddleButtonUp (MOUSEINFO *mi);
|
||||
virtual void OnMiddleButtonDown (MOUSEINFO *mi);
|
||||
};
|
||||
void MouseRptParser::OnMouseMove(MOUSEINFO *mi)
|
||||
{
|
||||
printf("Pos={%d,%d}\r\n", mi->dX, mi->dY);
|
||||
};
|
||||
void MouseRptParser::OnLeftButtonUp (MOUSEINFO *mi)
|
||||
{
|
||||
printf("L Butt Up\r\n");
|
||||
};
|
||||
void MouseRptParser::OnLeftButtonDown (MOUSEINFO *mi)
|
||||
{
|
||||
printf("L Butt Dn\r\n");
|
||||
};
|
||||
void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi)
|
||||
{
|
||||
printf("R Butt Up\r\n");
|
||||
};
|
||||
void MouseRptParser::OnRightButtonDown (MOUSEINFO *mi)
|
||||
{
|
||||
printf("R Butt Dn\r\n");
|
||||
};
|
||||
void MouseRptParser::OnMiddleButtonUp (MOUSEINFO *mi)
|
||||
{
|
||||
printf("M Butt Up\r\n");
|
||||
};
|
||||
void MouseRptParser::OnMiddleButtonDown (MOUSEINFO *mi)
|
||||
{
|
||||
printf("M Butt Dn\r\n");
|
||||
};
|
||||
// Accessory descriptor. It's how Arduino identifies itself to Android.
|
||||
char applicationName[] = "Arduino_Terminal"; // the app on your phone
|
||||
char accessoryName[] = "Arduino Due X"; // your Arduino board
|
||||
char companyName[] = "Arduino SA";
|
||||
|
||||
// Make up anything you want for these
|
||||
char versionNumber[] = "1.0";
|
||||
char serialNumber[] = "1";
|
||||
char url[] = "http://labs.arduino.cc/uploads/ADK/ArduinoTerminal/ThibaultTerminal_ICS_0001.apk";
|
||||
|
||||
USBHost Usb;
|
||||
HIDBoot<HID_PROTOCOL_MOUSE> HostMouse(&Usb);
|
||||
MouseRptParser Prs;
|
||||
ADK adk(&Usb, companyName, applicationName, accessoryName,versionNumber,url,serialNumber);
|
||||
|
||||
void setup()
|
||||
{
|
||||
cpu_irq_enable();
|
||||
printf("\r\nProgram started:\r\n");
|
||||
printf("\r\nADK demo start\r\n");
|
||||
delay(200);
|
||||
|
||||
HostMouse.SetReportParser(0,(HIDReportParser*)&Prs);
|
||||
}
|
||||
|
||||
#define RCVSIZE 128
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t buf[RCVSIZE];
|
||||
uint32_t nbread = 0;
|
||||
char helloworld[] = "Hello World!\r\n";
|
||||
|
||||
Usb.Task();
|
||||
|
||||
if (adk.isReady())
|
||||
{
|
||||
/* Write hello string to ADK */
|
||||
adk.write(strlen(helloworld), (uint8_t *)helloworld);
|
||||
|
||||
delay(1000);
|
||||
|
||||
/* Read data from ADK and print to UART */
|
||||
adk.read(&nbread, RCVSIZE, buf);
|
||||
if (nbread > 0)
|
||||
{
|
||||
printf("RCV: ");
|
||||
for (uint32_t i = 0; i < nbread; ++i)
|
||||
{
|
||||
printf("%c", (char)buf[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ Circuits At Home, LTD
|
||||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
/* USB functions */
|
||||
|
||||
#include "Arduino.h"
|
||||
@ -24,9 +25,9 @@ static uint32_t usb_error = 0;
|
||||
static uint32_t usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
* \brief USBHost class constructor.
|
||||
*/
|
||||
USBHost::USBHost () : bmHubPre(0)
|
||||
USBHost::USBHost() : bmHubPre(0)
|
||||
{
|
||||
// Set up state machine
|
||||
usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
|
||||
@ -36,7 +37,7 @@ USBHost::USBHost () : bmHubPre(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize data structures.
|
||||
* \brief Initialize USBHost class.
|
||||
*/
|
||||
void USBHost::init()
|
||||
{
|
||||
@ -44,8 +45,11 @@ void USBHost::init()
|
||||
bmHubPre = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get USB state.
|
||||
* \brief Get USBHost state.
|
||||
*
|
||||
* \return USB enumeration status (see USBHost::task).
|
||||
*/
|
||||
uint32_t USBHost::getUsbTaskState(void)
|
||||
{
|
||||
@ -53,7 +57,9 @@ uint32_t USBHost::getUsbTaskState(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set USB state.
|
||||
* \brief Set USB state.
|
||||
*
|
||||
* \param state New USBHost status to be set.
|
||||
*/
|
||||
void USBHost::setUsbTaskState(uint32_t state)
|
||||
{
|
||||
@ -61,7 +67,15 @@ void USBHost::setUsbTaskState(uint32_t state)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get end point info from address.
|
||||
* \brief Get endpoint info from USB device address and device endpoint.
|
||||
*
|
||||
* \note This function should be used to know which host pipe is being used for
|
||||
* the corresponding device endpoint.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
*
|
||||
* \return Pointer to an EpInfo structure.
|
||||
*/
|
||||
EpInfo* USBHost::getEpInfoEntry(uint32_t addr, uint32_t ep)
|
||||
{
|
||||
@ -74,18 +88,27 @@ EpInfo* USBHost::getEpInfoEntry(uint32_t addr, uint32_t ep)
|
||||
|
||||
for (uint32_t i = 0; i < p->epcount; i++)
|
||||
{
|
||||
if (pep->epAddr == ep)
|
||||
if (pep->deviceEpNum == ep)
|
||||
return pep;
|
||||
|
||||
pep++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set device end point entry.
|
||||
* Each device is different and has different number of endpoints.
|
||||
* This function plugs endpoint record structure, defined in application to devtable.
|
||||
* \brief Set device endpoint entry.
|
||||
*
|
||||
* \note Each device is different and has a different number of endpoints.
|
||||
* This function sets endpoint record structure to the device using address
|
||||
* addr in the address pool.
|
||||
*
|
||||
* \param ul_pipe Pipe address.
|
||||
* \param ul_token_type Token type.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL device not found.
|
||||
*/
|
||||
uint32_t USBHost::setEpInfoEntry(uint32_t addr, uint32_t epcount, EpInfo* eprecord_ptr)
|
||||
{
|
||||
@ -104,7 +127,21 @@ uint32_t USBHost::setEpInfoEntry(uint32_t addr, uint32_t epcount, EpInfo* epreco
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t USBHost::SetAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit)
|
||||
/**
|
||||
* \brief Set host pipe target address and set ppep pointer to the endpoint
|
||||
* structure matching the specified USB device address and endpoint.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param ppep Endpoint info structure pointer set by setPipeAddress.
|
||||
* \param nak_limit Maximum number of NAK permitted.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL device not found.
|
||||
* \retval USB_ERROR_EPINFO_IS_NULL no endpoint structure found for this device.
|
||||
* \retval USB_ERROR_EP_NOT_FOUND_IN_TBL the specified device endpoint cannot be found.
|
||||
*/
|
||||
uint32_t USBHost::setPipeAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit)
|
||||
{
|
||||
UsbDevice *p = addrPool.GetUsbDevicePtr(addr);
|
||||
|
||||
@ -119,29 +156,34 @@ uint32_t USBHost::SetAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t
|
||||
if (!*ppep)
|
||||
return USB_ERROR_EP_NOT_FOUND_IN_TBL;
|
||||
|
||||
nak_limit = (0x0001UL << ( ( (*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower) );
|
||||
nak_limit = (0x0001UL << (((*ppep)->bmNakPower > USB_NAK_MAX_POWER ) ? USB_NAK_MAX_POWER : (*ppep)->bmNakPower));
|
||||
nak_limit--;
|
||||
|
||||
// Set peripheral address
|
||||
//regWr( rPERADDR, addr );
|
||||
uhd_configure_address(ep, addr);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////// Y A TIL QQCHOSE A FAIRE???
|
||||
//uint8_t mode = regRd( rMODE );
|
||||
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
|
||||
//regWr( rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
|
||||
TRACE_USBHOST(printf(" => SetAddress deviceEP=%lu configued as hostPIPE=%lu sending to address=%lu\r\n", ep, (*ppep)->hostPipeNum, addr);)
|
||||
uhd_configure_address((*ppep)->hostPipeNum, addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a control request.
|
||||
* Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer depending on request.
|
||||
* Actual requests are defined as inlines.
|
||||
* \brief Send a control request.
|
||||
* Sets address, endpoint, fills control packet with necessary data, dispatches
|
||||
* control packet, and initiates bulk IN transfer depending on request.
|
||||
*
|
||||
* return codes:
|
||||
* 00 = success
|
||||
* 01-0f = non-zero HRSLT
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param bmReqType Request direction.
|
||||
* \param bRequest Request type.
|
||||
* \param wValLo Value low.
|
||||
* \param wValHi Value high.
|
||||
* \param wInd Index field.
|
||||
* \param total Request length.
|
||||
* \param nbytes Number of bytes to read.
|
||||
* \param dataptr Data pointer.
|
||||
* \param p USB class reader.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint32_t nbytes, uint8_t* dataptr, USBReadParser *p)
|
||||
{
|
||||
@ -156,12 +198,13 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t
|
||||
TRACE_USBHOST(printf(" => ctrlReq\r\n");)
|
||||
|
||||
// Set peripheral address
|
||||
rcode = SetAddress(addr, ep, &pep, nak_limit);
|
||||
rcode = setPipeAddress(addr, ep, &pep, nak_limit);
|
||||
if (rcode)
|
||||
return rcode;
|
||||
|
||||
// Allocate EP0 with default 8 bytes size if not already initialized
|
||||
rcode = UHD_EP0_Alloc(0, 8);
|
||||
// Allocate Pipe0 with default 64 bytes size if not already initialized
|
||||
// TODO : perform a get device descriptor first to get device endpoint size (else data can be missed if device ep0 > host pipe0)
|
||||
rcode = UHD_Pipe0_Alloc(0, 64);
|
||||
if (rcode)
|
||||
{
|
||||
TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : EP0 allocation error: %lu\r\n", rcode);)
|
||||
@ -169,7 +212,7 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t
|
||||
}
|
||||
|
||||
// Determine request direction
|
||||
direction = (( bmReqType & 0x80 ) > 0);
|
||||
direction = ((bmReqType & 0x80 ) > 0);
|
||||
|
||||
// Fill in setup packet
|
||||
setup_pkt.ReqType_u.bmRequestType = bmReqType;
|
||||
@ -180,12 +223,11 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t
|
||||
setup_pkt.wLength = total;
|
||||
|
||||
// Configure and write the setup packet into the FIFO
|
||||
//bytesWr(rSUDFIFO, 8, (uint8_t *)&setup_pkt);
|
||||
uhd_configure_pipe_token(0, tokSETUP);
|
||||
UHD_EP_Write(ep, 8, (uint8_t *)&setup_pkt);
|
||||
UHD_Pipe_Write(pep->hostPipeNum, 8, (uint8_t *)&setup_pkt);
|
||||
|
||||
// Dispatch packet
|
||||
rcode = dispatchPkt(tokSETUP, ep, nak_limit);
|
||||
rcode = dispatchPkt(tokSETUP, pep->hostPipeNum, nak_limit);
|
||||
if (rcode)
|
||||
{
|
||||
// Return HRSLT if not zero
|
||||
@ -224,7 +266,6 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t
|
||||
else
|
||||
{
|
||||
// OUT transfer
|
||||
//devtable[addr].epinfo[ep].sndToggle = bmSNDTOG1;
|
||||
TRACE_USBHOST(printf(" => ctrlData OUT\r\n");)
|
||||
rcode = OutTransfer(pep, nak_limit, nbytes, dataptr);
|
||||
}
|
||||
@ -237,27 +278,36 @@ uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t
|
||||
}
|
||||
|
||||
// Status stage
|
||||
return dispatchPkt((direction) ? tokOUTHS : tokINHS, ep, nak_limit );
|
||||
return dispatchPkt((direction) ? tokOUTHS : tokINHS, pep->hostPipeNum, nak_limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* IN transfer to arbitrary endpoint.
|
||||
* Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes.
|
||||
* Keep sending INs and writes data to memory area pointed by 'data'.
|
||||
* rcode 0 if no errors
|
||||
* 01-0f is relayed from dispatchPkt()
|
||||
* f0 means RCVDAVIRQ error
|
||||
* fe USB xfer timeout
|
||||
* \brief Perform IN request to the specified USB device.
|
||||
*
|
||||
* \note This function handles multiple packets (if necessary) and can
|
||||
* receive a maximum of 'nbytesptr' bytes. It keep sending INs and writes data
|
||||
* to memory area pointed by 'data'. The actual amount of received bytes is
|
||||
* stored in 'nbytesptr'.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param nbytesptr Receive buffer size. It is set to the amount of received
|
||||
* bytes when the function returns.
|
||||
* \param data Buffer to store received data.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::inTransfer(uint32_t addr, uint32_t ep, uint32_t *nbytesptr, uint8_t* data)
|
||||
{
|
||||
EpInfo *pep = NULL;
|
||||
uint32_t nak_limit = 0;
|
||||
|
||||
uint32_t rcode = SetAddress(addr, ep, &pep, nak_limit);
|
||||
uint32_t rcode = setPipeAddress(addr, ep, &pep, nak_limit);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
return rcode;
|
||||
}
|
||||
|
||||
return InTransfer(pep, nak_limit, nbytesptr, data);
|
||||
}
|
||||
@ -266,43 +316,34 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytespt
|
||||
{
|
||||
uint32_t rcode = 0;
|
||||
uint32_t pktsize = 0;
|
||||
uint16_t nbytes = *nbytesptr;
|
||||
uint8_t maxpktsize = pep->maxPktSize;
|
||||
uint32_t nbytes = *nbytesptr;
|
||||
uint32_t maxpktsize = pep->maxPktSize;
|
||||
|
||||
*nbytesptr = 0;
|
||||
|
||||
// Set toggle value
|
||||
//regWr(rHCTL, devtable[addr].epinfo[ep].rcvToggle);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Use a 'return' to exit this loop
|
||||
// IN packet to EP-'endpoint'. Function takes care of NAKS.
|
||||
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit);
|
||||
rcode = dispatchPkt(tokIN, pep->hostPipeNum, nak_limit);
|
||||
if (rcode)
|
||||
{
|
||||
// Should be 0, indicating ACK. Else return error code.
|
||||
return (rcode);
|
||||
if (rcode == 1)
|
||||
{
|
||||
// Pipe freeze is mandatory to avoid sending IN endlessly (else reception becomes messy then)
|
||||
uhd_freeze_pipe(pep->hostPipeNum);
|
||||
}
|
||||
// Should be 1, indicating NAK. Else return error code.
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// check for RCVDAVIRQ and generate error if not present
|
||||
// the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that
|
||||
/*if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0)
|
||||
{
|
||||
// Receive error
|
||||
return (0xf0);
|
||||
}*/
|
||||
|
||||
// Number of received bytes
|
||||
//pktsize = regRd(rRCVBC);
|
||||
//data = bytesRd(rRCVFIFO, pktsize, data);
|
||||
pktsize = uhd_byte_count(pep->epAddr);
|
||||
pktsize = uhd_byte_count(pep->hostPipeNum);
|
||||
if (nbytes < pktsize)
|
||||
printf("ce test n'a pas ete fait...\r\n");
|
||||
data += UHD_EP_Read(pep->epAddr, pktsize, data);
|
||||
|
||||
// Clear the IRQ & free the buffer
|
||||
//regWr(rHIRQ, bmRCVDAVIRQ);
|
||||
{
|
||||
TRACE_USBHOST(printf("/!\\ USBHost::InTransfer : receive buffer is too small, size=%lu, expected=%lu\r\n", nbytes, pktsize);)
|
||||
}
|
||||
data += UHD_Pipe_Read(pep->hostPipeNum, pktsize, data);
|
||||
|
||||
// Add this packet's byte count to total transfer length
|
||||
*nbytesptr += pktsize;
|
||||
@ -312,155 +353,116 @@ uint32_t USBHost::InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytespt
|
||||
// 2. 'nbytes' have been transferred.
|
||||
if ((pktsize < maxpktsize) || (*nbytesptr >= nbytes))
|
||||
{
|
||||
/*// Have we transferred 'nbytes' bytes?
|
||||
if (regRd(rHRSL) & bmRCVTOGRD)
|
||||
{
|
||||
// Save toggle value
|
||||
devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG1;
|
||||
}
|
||||
else
|
||||
{
|
||||
devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG0;
|
||||
}*/
|
||||
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OUT transfer to arbitrary endpoint.
|
||||
* Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes.
|
||||
* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer
|
||||
* rcode 0 if no errors
|
||||
* 01-0f is relayed from HRSL
|
||||
* \brief Perform OUT request to the specified USB device.
|
||||
*
|
||||
* Major part of this function borrowed from code shared by Richard Ibbotson
|
||||
* \note This function handles multiple packets (if necessary) and sends
|
||||
* 'nbytes' bytes.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param nbytes Buffer size to be sent.
|
||||
* \param data Buffer to send.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::outTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data)
|
||||
{
|
||||
/*
|
||||
EpInfo *pep = NULL;
|
||||
uint16_t nak_limit;
|
||||
EpInfo *pep = NULL;
|
||||
uint32_t nak_limit = 0;
|
||||
|
||||
uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
|
||||
uint32_t rcode = setPipeAddress(addr, ep, &pep, nak_limit);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
return rcode;
|
||||
}
|
||||
|
||||
return OutTransfer(pep, nak_limit, nbytes, data);
|
||||
*/
|
||||
printf("j'ai beau etre matinal.. j'ai mal!!!!\r\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t USBHost::OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, uint8_t *data)
|
||||
{
|
||||
/*
|
||||
uint8_t rcode, retry_count;
|
||||
uint8_t *data_p = data; //local copy of the data pointer
|
||||
uint16_t bytes_tosend, nak_count;
|
||||
uint16_t bytes_left = nbytes;
|
||||
uint32_t rcode = 0;
|
||||
uint32_t bytes_tosend = 0;
|
||||
uint32_t bytes_left = nbytes;
|
||||
uint32_t maxpktsize = pep->maxPktSize;
|
||||
|
||||
uint8_t maxpktsize = pep->maxPktSize;
|
||||
|
||||
if (maxpktsize < 1 || maxpktsize > 64)
|
||||
if (maxpktsize < 1)
|
||||
return USB_ERROR_INVALID_MAX_PKT_SIZE;
|
||||
|
||||
unsigned long timeout = millis() + USB_XFER_TIMEOUT;
|
||||
|
||||
regWr( rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0 ); //set toggle value
|
||||
|
||||
while( bytes_left )
|
||||
while (bytes_left)
|
||||
{
|
||||
retry_count = 0;
|
||||
nak_count = 0;
|
||||
bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
|
||||
bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO
|
||||
regWr( rSNDBC, bytes_tosend ); //set number of bytes
|
||||
regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet
|
||||
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
|
||||
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
|
||||
rcode = ( regRd( rHRSL ) & 0x0f );
|
||||
bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left;
|
||||
|
||||
while( rcode && ( timeout > millis()))
|
||||
// Write FIFO
|
||||
UHD_Pipe_Write(pep->hostPipeNum, bytes_tosend, data);
|
||||
|
||||
// Use a 'return' to exit this loop
|
||||
// OUT packet to EP-'endpoint'. Function takes care of NAKS.
|
||||
rcode = dispatchPkt(tokOUT, pep->hostPipeNum, nak_limit);
|
||||
if (rcode)
|
||||
{
|
||||
switch( rcode )
|
||||
{
|
||||
case hrNAK:
|
||||
nak_count ++;
|
||||
if( nak_limit && ( nak_count == nak_limit ))
|
||||
return( rcode );
|
||||
break;
|
||||
case hrTIMEOUT:
|
||||
retry_count ++;
|
||||
if( retry_count == USB_RETRY_LIMIT )
|
||||
return( rcode );
|
||||
break;
|
||||
default:
|
||||
return( rcode );
|
||||
}//switch( rcode
|
||||
// Should be 0, indicating ACK. Else return error code.
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// process NAK according to Host out NAK bug
|
||||
regWr( rSNDBC, 0 );
|
||||
regWr( rSNDFIFO, *data_p );
|
||||
regWr( rSNDBC, bytes_tosend );
|
||||
regWr( rHXFR, ( tokOUT | pep->epAddr )); //dispatch packet
|
||||
while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ
|
||||
regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ
|
||||
rcode = ( regRd( rHRSL ) & 0x0f );
|
||||
}//while( rcode && ....
|
||||
bytes_left -= bytes_tosend;
|
||||
data_p += bytes_tosend;
|
||||
}//while( bytes_left...
|
||||
pep->bmSndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
|
||||
return( rcode ); //should be 0 in all cases
|
||||
*/
|
||||
printf("j'ai beau etre matinal.. j'ai mal!!!! arggghh\r\n");
|
||||
return 1;
|
||||
data += bytes_tosend;
|
||||
}
|
||||
|
||||
// Should be 0 in all cases
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch USB packet.
|
||||
* Assumes peripheral address is set and relevant buffer is loaded/empty.
|
||||
* \brief Dispatch USB packet.
|
||||
*
|
||||
* \note Ensure peripheral address is set and relevant buffer is loaded/empty.
|
||||
* If NAK, tries to re-send up to nak_limit times.
|
||||
* If nak_limit == 0, do not count NAKs, exit after timeout.
|
||||
* If bus timeout, re-sends up to USB_RETRY_LIMIT times.
|
||||
* rcode 0 for success
|
||||
* 1 for naked
|
||||
* 2 for timeout
|
||||
*
|
||||
* Note: pipe token MUST be configured first when the corresponding FIFO is used,
|
||||
* else packet may be corrupted.
|
||||
* \param token Token type (Setup, In or Out).
|
||||
* \param hostPipeNum Host pipe number to use for sending USB packet.
|
||||
* \param nak_limit Maximum number of NAK permitted.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t ep, uint32_t nak_limit)
|
||||
uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t hostPipeNum, uint32_t nak_limit)
|
||||
{
|
||||
uint32_t timeout = millis() + USB_XFER_TIMEOUT;
|
||||
uint32_t nak_count = 0;
|
||||
uint32_t rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
||||
|
||||
TRACE_USBHOST(printf(" => dispatchPkt token=%lu\r\n", token);)
|
||||
TRACE_USBHOST(printf(" => dispatchPkt token=%lu pipe=%lu nak_limit=%lu\r\n", token, hostPipeNum, nak_limit);)
|
||||
|
||||
// Launch the transfer
|
||||
//regWr(rHXFR, (token | ep));
|
||||
UHD_EP_Send(ep, token);
|
||||
UHD_Pipe_Send(hostPipeNum, token);
|
||||
|
||||
while (timeout > millis())
|
||||
// Check timeout but don't hold timeout if VBUS is lost
|
||||
while ((timeout > millis()) && (UHD_GetVBUSState() == UHD_STATE_CONNECTED))
|
||||
{
|
||||
// Wait for transfer completion
|
||||
if (UHD_EP_Is_Transfer_Complete(ep, token))
|
||||
if (UHD_Pipe_Is_Transfer_Complete(hostPipeNum, token))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
if (Is_uhd_nak_received(ep))
|
||||
// Is NAK received?
|
||||
if (Is_uhd_nak_received(hostPipeNum))
|
||||
{
|
||||
uhd_ack_nak_received(ep);
|
||||
uhd_ack_nak_received(hostPipeNum);
|
||||
nak_count++;
|
||||
|
||||
if (nak_limit && (nak_count == nak_limit))
|
||||
{
|
||||
return 1; //////////////////////////// cree un code pour ca
|
||||
// Return NAK
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -469,8 +471,14 @@ uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t ep, uint32_t nak_limit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a device using known device classes.
|
||||
* \brief Configure device using known device classes.
|
||||
* The device get a new address even if its class remain unknown.
|
||||
*
|
||||
* \param parent USB device address of the device's parent (0 if root).
|
||||
* \param port USB device base address (see AddressPoolImpl).
|
||||
* \param lowspeed Device speed.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||
{
|
||||
@ -490,11 +498,20 @@ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE))
|
||||
|
||||
if (rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
|
||||
{
|
||||
TRACE_USBHOST(printf("USBHost::Configuring : ERROR : device not supported!\r\n");)
|
||||
}
|
||||
else if (rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)
|
||||
{
|
||||
TRACE_USBHOST(printf("USBHost::Configuring : ERROR : class instance already in use!\r\n");)
|
||||
}
|
||||
else
|
||||
{
|
||||
// in case of an error devConfigIndex should be reset to 0
|
||||
// in order to start from the very beginning the
|
||||
// next time the program gets here
|
||||
// in order to start from the very beginning the next time
|
||||
// the program gets here
|
||||
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
||||
devConfigIndex = 0;
|
||||
|
||||
@ -502,7 +519,7 @@ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||
}
|
||||
}
|
||||
|
||||
// if we get here that means that the device class is not supported by any of registered classes
|
||||
// Device class is not supported by any of the registered classes
|
||||
devConfigIndex = 0;
|
||||
|
||||
rcode = DefaultAddressing(parent, port, lowspeed);
|
||||
@ -510,6 +527,15 @@ uint32_t USBHost::Configuring(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Configure device with unknown USB class.
|
||||
*
|
||||
* \param parent USB device address of the device's parent (0 if root).
|
||||
* \param port USB device base address (see AddressPoolImpl).
|
||||
* \param lowspeed Device speed.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::DefaultAddressing(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||
{
|
||||
uint32_t rcode = 0;
|
||||
@ -553,30 +579,70 @@ uint32_t USBHost::DefaultAddressing(uint32_t parent, uint32_t port, uint32_t low
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Release device and free associated resources.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::ReleaseDevice(uint32_t addr)
|
||||
{
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
||||
{
|
||||
if (devConfig[i]->GetAddress() == addr)
|
||||
{
|
||||
return devConfig[i]->Release();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get device descriptor
|
||||
/**
|
||||
* \brief Get device descriptor.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param nbytes Buffer size.
|
||||
* \param dataptr Buffer to store received descriptor.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::getDevDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr)
|
||||
{
|
||||
return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, nbytes, dataptr, 0));
|
||||
}
|
||||
|
||||
// Get configuration descriptor
|
||||
/**
|
||||
* \brief Get configuration descriptor.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param nbytes Buffer size.
|
||||
* \param conf Configuration number.
|
||||
* \param dataptr Buffer to store received descriptor.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint32_t conf, uint8_t* dataptr)
|
||||
{
|
||||
return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get configuration descriptor and extract endpoints using USBReadParser object.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param conf Configuration number.
|
||||
* \param p USBReadParser object pointer used to extract endpoints.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBReadParser *p)
|
||||
{
|
||||
const uint32_t bufSize = 64;
|
||||
@ -593,28 +659,56 @@ uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBRea
|
||||
return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, total, bufSize, buf, p));
|
||||
}
|
||||
|
||||
// Get string descriptor
|
||||
uint32_t USBHost::getStrDescr(uint32_t addr, uint32_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr)
|
||||
/**
|
||||
* \brief Get string descriptor.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param nbytes Buffer size.
|
||||
* \param index String index.
|
||||
* \param langid Language ID.
|
||||
* \param dataptr Buffer to store received descriptor.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::getStrDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr)
|
||||
{
|
||||
return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, ns, ns, dataptr, 0));
|
||||
return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nbytes, nbytes, dataptr, 0));
|
||||
}
|
||||
|
||||
// Set address
|
||||
/**
|
||||
* \brief Set USB device address.
|
||||
*
|
||||
* \param oldaddr Current USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param addr New USB device address to be set.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::setAddr(uint32_t oldaddr, uint32_t ep, uint32_t newaddr)
|
||||
{
|
||||
TRACE_USBHOST(printf(" => setAddr\r\n");)
|
||||
TRACE_USBHOST(printf(" => USBHost::setAddr\r\n");)
|
||||
return ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0x0000, 0, 0);
|
||||
}
|
||||
|
||||
// Set configuration
|
||||
/**
|
||||
* \brief Set configuration.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
* \param ep USB device endpoint number.
|
||||
* \param conf_value New configuration value to be set.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t USBHost::setConf(uint32_t addr, uint32_t ep, uint32_t conf_value)
|
||||
{
|
||||
return (ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0x0000, 0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* USB main task.
|
||||
* Performs enumeration/cleanup.
|
||||
* \brief USB main task, responsible for enumeration and clean up stage.
|
||||
*
|
||||
* \note Must be periodically called from loop().
|
||||
*/
|
||||
void USBHost::Task(void)
|
||||
{
|
||||
@ -648,16 +742,17 @@ void USBHost::Task(void)
|
||||
{
|
||||
delay = millis() + USB_SETTLE_DELAY;
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
|
||||
///////////////////////////////////////////////////////////lowspeed = 0 ou 1; faire un get speed
|
||||
//FIXME TODO: lowspeed = 0 ou 1; already done by hardware?
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Poll connected devices (if required)
|
||||
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
||||
if (devConfig[i])
|
||||
rcode = devConfig[i]->Poll();
|
||||
|
||||
// USB state machine
|
||||
// Perform USB enumeration stage and clean up
|
||||
switch (usb_task_state)
|
||||
{
|
||||
case USB_DETACHED_SUBSTATE_INITIALIZE:
|
||||
@ -667,6 +762,7 @@ void USBHost::Task(void)
|
||||
UHD_Init();
|
||||
init();
|
||||
|
||||
// Free all USB resources
|
||||
for (uint32_t i = 0; i < USB_NUMDEVICES; ++i)
|
||||
if (devConfig[i])
|
||||
rcode = devConfig[i]->Release();
|
||||
|
@ -19,8 +19,8 @@ e-mail : support@circuitsathome.com
|
||||
#ifndef USB_H_INCLUDED
|
||||
#define USB_H_INCLUDED
|
||||
|
||||
#define TRACE_USBHOST(x) x
|
||||
//#define TRACE_USBHOST(x)
|
||||
//#define TRACE_USBHOST(x) x
|
||||
#define TRACE_USBHOST(x)
|
||||
|
||||
#include <stdint.h>
|
||||
#include "usb_ch9.h"
|
||||
@ -120,7 +120,11 @@ typedef struct
|
||||
uint16_t wLength; // 6 Depends on bRequest
|
||||
} SETUP_PKT, *PSETUP_PKT;
|
||||
|
||||
// Base class for incoming data parser
|
||||
/**
|
||||
* \class USBReadParser
|
||||
*
|
||||
* \brief Base class used for USB descriptor parsing.
|
||||
*/
|
||||
class USBReadParser
|
||||
{
|
||||
public:
|
||||
@ -128,21 +132,30 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* USBDeviceConfig class.
|
||||
* \class USBDeviceConfig
|
||||
*
|
||||
* \brief Device configuration class used for managing device life cycle.
|
||||
*/
|
||||
class USBDeviceConfig
|
||||
{
|
||||
public:
|
||||
//! @brief Perform final enumeration stage.
|
||||
virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed) = 0;
|
||||
|
||||
//! @brief Free USB allocated resources (pipes and address).
|
||||
virtual uint32_t Release() = 0;
|
||||
|
||||
//! @brief Poll USB device. Call is made for each connected USB device on USBHost.task() call.
|
||||
virtual uint32_t Poll() = 0;
|
||||
|
||||
//! @brief Retrieve USB device address.
|
||||
virtual uint32_t GetAddress() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* USBHost Class.
|
||||
* The device table is filled during enumeration.
|
||||
* Index corresponds to device address and each entry contains pointer to endpoint structure and device class to use.
|
||||
* \class USBHost
|
||||
*
|
||||
* \brief Main USB host class.
|
||||
*/
|
||||
class USBHost
|
||||
{
|
||||
@ -190,7 +203,7 @@ class USBHost
|
||||
uint32_t getDevDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr);
|
||||
uint32_t getConfDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint32_t conf, uint8_t* dataptr);
|
||||
uint32_t getConfDescr(uint32_t addr, uint32_t ep, uint32_t conf, USBReadParser *p);
|
||||
uint32_t getStrDescr(uint32_t addr, uint32_t ep, uint16_t ns, uint8_t index, uint16_t langid, uint8_t* dataptr);
|
||||
uint32_t getStrDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
|
||||
uint32_t setAddr(uint32_t oldaddr, uint32_t ep, uint32_t newaddr);
|
||||
uint32_t setConf(uint32_t addr, uint32_t ep, uint32_t conf_value);
|
||||
uint32_t ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
@ -209,7 +222,7 @@ class USBHost
|
||||
|
||||
private:
|
||||
void init();
|
||||
uint32_t SetAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit);
|
||||
uint32_t setPipeAddress(uint32_t addr, uint32_t ep, EpInfo **ppep, uint32_t &nak_limit);
|
||||
uint32_t OutTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t nbytes, uint8_t *data);
|
||||
uint32_t InTransfer(EpInfo *pep, uint32_t nak_limit, uint32_t *nbytesptr, uint8_t* data);
|
||||
};
|
||||
|
@ -27,9 +27,22 @@ e-mail : support@circuitsathome.com
|
||||
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
|
||||
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
|
||||
|
||||
/**
|
||||
* \brief Device endpoint definition.
|
||||
*
|
||||
* \note hostPipeNum is the allocated pipe used for the communication with
|
||||
* deviceEpNum remote device endpoint.
|
||||
* There is exactly one hostPipeNum corresponding to a deviceEpNum.
|
||||
*
|
||||
* \note The number of host pipe is limited by the hardware (10 on SAM3X).
|
||||
* Moreover hostPipeNum allocation is static, meaning that only a limited
|
||||
* amount of device endpoints can be opened at the same time, thus limitating
|
||||
* the maximum number of connected devices at the same time.
|
||||
*/
|
||||
struct EpInfo
|
||||
{
|
||||
uint32_t epAddr; // Endpoint address
|
||||
uint32_t deviceEpNum; // Device endpoint number
|
||||
uint32_t hostPipeNum; // Host corresponding pipe number
|
||||
uint32_t maxPktSize; // Maximum packet size
|
||||
|
||||
union
|
||||
@ -45,15 +58,20 @@ struct EpInfo
|
||||
};
|
||||
};
|
||||
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// ---------------------------------
|
||||
// | | H | P | P | P | A | A | A |
|
||||
// ---------------------------------
|
||||
//
|
||||
// H - if 1 the address is a hub address
|
||||
// P - parent hub address
|
||||
// A - device address / port number in case of hub
|
||||
//
|
||||
/**
|
||||
* \brief USB device address definition.
|
||||
*
|
||||
* \note The 8 bits USB address is defined like this:
|
||||
*
|
||||
* 7 6 5 4 3 2 1 0
|
||||
* ---------------------------------
|
||||
* | | H | P | P | P | A | A | A |
|
||||
* ---------------------------------
|
||||
*
|
||||
* H - if 1 the address is a hub address
|
||||
* P - parent hub address
|
||||
* A - device address / port number in case of hub
|
||||
*/
|
||||
struct UsbDeviceAddress
|
||||
{
|
||||
union
|
||||
@ -73,6 +91,14 @@ struct UsbDeviceAddress
|
||||
#define bmUSB_DEV_ADDR_PARENT 0x38
|
||||
#define bmUSB_DEV_ADDR_HUB 0x40
|
||||
|
||||
/**
|
||||
* \brief USB device definition.
|
||||
*
|
||||
* \note epinfo is used to store the list of device endpoints currently used
|
||||
* by the USBHost stack. This field is set during enumeration process when
|
||||
* a supported USB class is found. See any USB classes implementing
|
||||
* USBDeviceConfig and init() method for reference.
|
||||
*/
|
||||
struct UsbDevice
|
||||
{
|
||||
EpInfo *epinfo; // endpoint info pointer
|
||||
@ -81,6 +107,9 @@ struct UsbDevice
|
||||
uint32_t lowspeed; // indicates if a device is the low speed one
|
||||
};
|
||||
|
||||
/**
|
||||
* \class Abstract AddressPool definition.
|
||||
*/
|
||||
class AddressPool
|
||||
{
|
||||
public:
|
||||
@ -94,28 +123,46 @@ typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
|
||||
#define ADDR_ERROR_INVALID_INDEX 0xFF
|
||||
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
|
||||
|
||||
/**
|
||||
* \class AddressPoolImpl definition.
|
||||
* Used to store the list of connected devices and to keep track of free USB
|
||||
* addresses.
|
||||
*/
|
||||
template <const uint32_t MAX_DEVICES_ALLOWED>
|
||||
class AddressPoolImpl : public AddressPool
|
||||
{
|
||||
private:
|
||||
|
||||
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
|
||||
EpInfo dev0ep; // Endpoint data structure used during enumeration for uninitialized device
|
||||
|
||||
uint32_t hubCounter; // hub counter is kept
|
||||
// in order to avoid hub address duplication
|
||||
|
||||
UsbDevice thePool[MAX_DEVICES_ALLOWED];
|
||||
|
||||
// Initializes address pool entry
|
||||
/**
|
||||
* \brief Initialize the specified address pool entry.
|
||||
*
|
||||
* \param index Index pointing to a UsbDevice instance in the address pool.
|
||||
*/
|
||||
void InitEntry(uint32_t index)
|
||||
{
|
||||
thePool[index].address = 0;
|
||||
thePool[index].epcount = 1;
|
||||
thePool[index].address = 0;
|
||||
thePool[index].epcount = 1;
|
||||
thePool[index].lowspeed = 0;
|
||||
thePool[index].epinfo = &dev0ep;
|
||||
thePool[index].epinfo = &dev0ep;
|
||||
};
|
||||
|
||||
// Returns thePool index for a given address
|
||||
/**
|
||||
* \brief Return an address pool index for a given address. This index can
|
||||
* further be used to retrieve the corresponding USB device instance
|
||||
* UsbDevice.
|
||||
*
|
||||
* \param index Index pointing to a UsbDevice instance in the address pool.
|
||||
*
|
||||
* \return Index number if found, 0 otherwise.
|
||||
* \note Index 0 is reserved for address 0 and shall never be used.
|
||||
*/
|
||||
uint32_t FindAddressIndex(uint32_t address = 0)
|
||||
{
|
||||
for (uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
@ -126,21 +173,45 @@ private:
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Returns thePool child index for a given parent
|
||||
/**
|
||||
* \brief Return address pool child index for a given parent. This index can
|
||||
* further be used to retrieve the corresponding USB device instance
|
||||
* UsbDevice.
|
||||
*
|
||||
* \param addr Parent USB address.
|
||||
* \param start Search in the pool from this index. Calling multiple time
|
||||
* this function with the returned index + 1 can be used to walk through
|
||||
* all children.
|
||||
*
|
||||
* \return Child index number if found, 0 otherwise.
|
||||
* \note Index 0 is reserved for address 0 and shall never be used.
|
||||
*/
|
||||
uint32_t FindChildIndex(UsbDeviceAddress addr, uint32_t start = 1)
|
||||
{
|
||||
for (uint32_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++)
|
||||
for (uint32_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; ++i)
|
||||
{
|
||||
if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Frees address entry specified by index parameter
|
||||
/**
|
||||
* \brief Free address entry specified by index parameter.
|
||||
*
|
||||
* \note Calling FreeAddressByIndex only frees the USB address for possible
|
||||
* further assignement. However, it does not free the actual USB resources
|
||||
* used by the device. This can be made by calling the release() method
|
||||
* from any UsbDevice class implementing USBDeviceConfig.
|
||||
*
|
||||
* \param index Index pointing to a UsbDevice instance in the address pool.
|
||||
*
|
||||
* \note Calling FreeAddressByIndex with a 0 index param has no effect.
|
||||
*/
|
||||
void FreeAddressByIndex(uint32_t index)
|
||||
{
|
||||
// Zerro field is reserved and should not be affected
|
||||
// Zero field is reserved and should not be affected
|
||||
if (index == 0)
|
||||
return;
|
||||
|
||||
@ -154,10 +225,13 @@ private:
|
||||
if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
|
||||
hubCounter --;
|
||||
}
|
||||
|
||||
InitEntry(index);
|
||||
}
|
||||
|
||||
// Initializes the whole address pool at once
|
||||
/**
|
||||
* \brief Initialize all address poll entries at once.
|
||||
*/
|
||||
void InitAllAddresses()
|
||||
{
|
||||
for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
|
||||
@ -167,6 +241,9 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief AddressPoolImpl class constructor.
|
||||
*/
|
||||
AddressPoolImpl() : hubCounter(0)
|
||||
{
|
||||
// Init address zero (reserved)
|
||||
@ -176,11 +253,18 @@ public:
|
||||
InitAllAddresses();
|
||||
|
||||
// Configure ep0 used for enumeration
|
||||
dev0ep.epAddr = 0;
|
||||
dev0ep.maxPktSize = 8;
|
||||
dev0ep.deviceEpNum = 0;
|
||||
dev0ep.hostPipeNum = 0;
|
||||
dev0ep.maxPktSize = 8;
|
||||
};
|
||||
|
||||
// Returns a pointer to a specified address entry
|
||||
/**
|
||||
* \brief Get a UsbDevice pointer from a USB device address.
|
||||
*
|
||||
* \param addr USB device address.
|
||||
*
|
||||
* \return UsbDevice pointer on success, 0 otherwise.
|
||||
*/
|
||||
virtual UsbDevice* GetUsbDevicePtr(uint32_t addr)
|
||||
{
|
||||
if (!addr)
|
||||
@ -191,7 +275,12 @@ public:
|
||||
return (!index) ? 0 : (thePool + index);
|
||||
};
|
||||
|
||||
// Performs an operation specified by pfunc for each addressed device
|
||||
/**
|
||||
* \brief Perform an operation specified by pfunc for each addressed
|
||||
* USB device.
|
||||
*
|
||||
* \param pfunc Any function pointer with type UsbDeviceHandleFunc.
|
||||
*/
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
|
||||
{
|
||||
if (!pfunc)
|
||||
@ -202,7 +291,18 @@ public:
|
||||
pfunc(thePool + i);
|
||||
};
|
||||
|
||||
// Allocates new address
|
||||
/**
|
||||
* \brief Allocate a new USB device address.
|
||||
*
|
||||
* \note See UsbDeviceAddress definition for better understanding.
|
||||
*
|
||||
* \param parent USB device address of the Parent device.
|
||||
* \param is_hub Set to true if the corresponding device is a Hub, false
|
||||
* otherwise.
|
||||
* \param port USB device base address.
|
||||
*
|
||||
* \return UsbDevice pointer on success, 0 otherwise.
|
||||
*/
|
||||
virtual uint32_t AllocAddress(uint32_t parent, uint32_t is_hub = 0, uint32_t port = 0)
|
||||
{
|
||||
if (parent > 127 || port > 7)
|
||||
@ -223,7 +323,7 @@ public:
|
||||
if (is_hub)
|
||||
{
|
||||
thePool[index].address = 0x41;
|
||||
hubCounter ++;
|
||||
hubCounter++;
|
||||
}
|
||||
else
|
||||
thePool[index].address = 1;
|
||||
@ -238,52 +338,51 @@ public:
|
||||
if (is_hub)
|
||||
{
|
||||
addr.bmHub = 1;
|
||||
addr.bmAddress = ++hubCounter;
|
||||
addr.bmAddress = hubCounter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr.bmHub = 0;
|
||||
addr.bmAddress = port;
|
||||
}
|
||||
|
||||
thePool[index].address = *((uint8_t*)&addr);
|
||||
/*
|
||||
Serial.print("Addr:");
|
||||
Serial.print(addr.bmHub, HEX);
|
||||
Serial.print(".");
|
||||
Serial.print(addr.bmParent, HEX);
|
||||
Serial.print(".");
|
||||
Serial.println(addr.bmAddress, HEX);
|
||||
*/
|
||||
|
||||
return thePool[index].address;
|
||||
};
|
||||
|
||||
// Empties pool entry
|
||||
/**
|
||||
* \brief Free the specified USB device address.
|
||||
*
|
||||
* \param addr USB device address to free.
|
||||
*/
|
||||
virtual void FreeAddress(uint32_t addr)
|
||||
{
|
||||
// if the root hub is disconnected all the addresses should be initialized
|
||||
// If the root hub is disconnected all the addresses should be initialized
|
||||
if (addr == 0x41)
|
||||
{
|
||||
InitAllAddresses();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t index = FindAddressIndex(addr);
|
||||
FreeAddressByIndex(index);
|
||||
};
|
||||
|
||||
// Returns number of hubs attached
|
||||
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
|
||||
/*uint8_t GetNumHubs()
|
||||
/*uint32_t GetNumHubs()
|
||||
{
|
||||
return hubCounter;
|
||||
};
|
||||
|
||||
uint8_t GetNumDevices()
|
||||
uint32_t GetNumDevices()
|
||||
{
|
||||
uint8_t counter = 0;
|
||||
uint32_t counter = 0;
|
||||
|
||||
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
|
||||
for (uint32_t i = 1; i < MAX_DEVICES_ALLOWED; ++i)
|
||||
if (thePool[i].address != 0);
|
||||
counter ++;
|
||||
counter++;
|
||||
|
||||
return counter;
|
||||
};*/
|
||||
|
405
hardware/arduino/sam/system/USBHost/adk.cpp
Normal file
405
hardware/arduino/sam/system/USBHost/adk.cpp
Normal file
@ -0,0 +1,405 @@
|
||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
/* Google ADK interface */
|
||||
|
||||
#include "adk.h"
|
||||
|
||||
const uint32_t ADK::epDataInIndex = 1;
|
||||
const uint32_t ADK::epDataOutIndex = 2;
|
||||
|
||||
/**
|
||||
* \brief ADK class constructor.
|
||||
*/
|
||||
ADK::ADK(USBHost *p, const char* pmanufacturer,
|
||||
const char* pmodel,
|
||||
const char* pdescription,
|
||||
const char* pversion,
|
||||
const char* puri,
|
||||
const char* pserial) :
|
||||
manufacturer(pmanufacturer),
|
||||
model(pmodel),
|
||||
description(pdescription),
|
||||
version(pversion),
|
||||
uri(puri),
|
||||
serial(pserial),
|
||||
pUsb(p),
|
||||
bAddress(0),
|
||||
bNumEP(1),
|
||||
ready(false)
|
||||
{
|
||||
// Initialize endpoint data structures
|
||||
for (uint32_t i = 0; i < ADK_MAX_ENDPOINTS; ++i)
|
||||
{
|
||||
epInfo[i].deviceEpNum = 0;
|
||||
epInfo[i].hostPipeNum = 0;
|
||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||
epInfo[i].epAttribs = 0;
|
||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||
}
|
||||
|
||||
// Register in USB subsystem
|
||||
if (pUsb)
|
||||
{
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize connection to an Android Phone.
|
||||
*
|
||||
* \param parent USB device address of the Parent device.
|
||||
* \param port USB device base address.
|
||||
* \param lowspeed USB device speed.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t ADK::Init(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||
{
|
||||
|
||||
uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
|
||||
uint32_t rcode = 0;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint32_t adkproto = -1;
|
||||
uint32_t num_of_conf = 0;
|
||||
|
||||
// Get memory address of USB device address pool
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
TRACE_USBHOST(printf("ADK::Init\r\n");)
|
||||
|
||||
// Check if address has already been assigned to an instance
|
||||
if (bAddress)
|
||||
{
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
}
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p)
|
||||
{
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo)
|
||||
{
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
goto FailGetDevDescr;
|
||||
}
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode)
|
||||
{
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
TRACE_USBHOST(printf("ADK::Init : setAddr failed with rcode %lu\r\n", rcode);)
|
||||
return rcode;
|
||||
}
|
||||
|
||||
TRACE_USBHOST(printf("ADK::Init : device address is now %lu\r\n", bAddress);)
|
||||
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
{
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
{
|
||||
goto FailSetDevTblEntry;
|
||||
}
|
||||
|
||||
// Check if ADK device is already in accessory mode; if yes, configure and exit
|
||||
if (((USB_DEVICE_DESCRIPTOR*)buf)->idVendor == ADK_VID &&
|
||||
(((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADK_PID || ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct == ADB_PID))
|
||||
{
|
||||
TRACE_USBHOST(printf("ADK::Init : Accessory mode device detected\r\n");)
|
||||
|
||||
/* Go through configurations, find first bulk-IN, bulk-OUT EP, fill epInfo and quit */
|
||||
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
|
||||
|
||||
TRACE_USBHOST(printf("ADK::Init : number of configuration is %lu\r\n", num_of_conf);)
|
||||
|
||||
for (uint32_t i = 0; i < num_of_conf; ++i)
|
||||
{
|
||||
ConfigDescParser<0, 0, 0, 0> confDescrParser(this);
|
||||
|
||||
delay(1);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
|
||||
#if defined(XOOM)
|
||||
//Added by Jaylen Scott Vanorden
|
||||
if (rcode)
|
||||
{
|
||||
TRACE_USBHOST(printf("ADK::Init : Got 1st bad code for config: %lu\r\n", rcode);)
|
||||
|
||||
// Try once more
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
goto FailGetConfDescr;
|
||||
}
|
||||
|
||||
if (bNumEP > 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bNumEP == 3)
|
||||
{
|
||||
// Assign epInfo to epinfo pointer - this time all 3 endpoins
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
if (rcode)
|
||||
{
|
||||
goto FailSetDevTblEntry;
|
||||
}
|
||||
}
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
if (rcode)
|
||||
{
|
||||
goto FailSetConf;
|
||||
}
|
||||
|
||||
TRACE_USBHOST(printf("ADK::Init : ADK device configured successfully\r\n");)
|
||||
ready = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Probe device - get accessory protocol revision
|
||||
delay(1);
|
||||
rcode = getProto((uint8_t*)&adkproto);
|
||||
|
||||
#if defined(XOOM)
|
||||
// Added by Jaylen Scott Vanorden
|
||||
if (rcode)
|
||||
{
|
||||
TRACE_USBHOST(printf("ADK::Init : Got 1st bad code for config: %lu\r\n", rcode);)
|
||||
|
||||
// Try once more
|
||||
rcode = getProto((uint8_t*)&adkproto );
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
goto FailGetProto;
|
||||
}
|
||||
TRACE_USBHOST(printf("ADK::Init : DK protocol rev. %lu", adkproto);)
|
||||
|
||||
// Send ID strings
|
||||
sendStr(ACCESSORY_STRING_MANUFACTURER, manufacturer);
|
||||
sendStr(ACCESSORY_STRING_MODEL, model);
|
||||
sendStr(ACCESSORY_STRING_DESCRIPTION, description);
|
||||
sendStr(ACCESSORY_STRING_VERSION, version);
|
||||
sendStr(ACCESSORY_STRING_URI, uri);
|
||||
sendStr(ACCESSORY_STRING_SERIAL, serial);
|
||||
|
||||
// Switch to accessory mode
|
||||
// The Android phone will reset
|
||||
rcode = switchAcc();
|
||||
if (rcode)
|
||||
{
|
||||
goto FailSwAcc;
|
||||
}
|
||||
rcode = -1;
|
||||
goto SwAttempt; // Switch to accessory mode
|
||||
|
||||
// Diagnostic messages
|
||||
FailGetDevDescr:
|
||||
TRACE_USBHOST(printf("ADK::Init getDevDescr : ");)
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
TRACE_USBHOST(printf("ADK::Init setDevTblEn : ");)
|
||||
goto Fail;
|
||||
|
||||
FailGetProto:
|
||||
TRACE_USBHOST(printf("ADK::Init getProto : ");)
|
||||
goto Fail;
|
||||
|
||||
FailSwAcc:
|
||||
TRACE_USBHOST(printf("ADK::Init swAcc : ");)
|
||||
goto Fail;
|
||||
|
||||
SwAttempt:
|
||||
TRACE_USBHOST(printf("ADK::Init Accessory mode switch attempt : ");)
|
||||
goto Fail;
|
||||
|
||||
FailGetConfDescr:
|
||||
TRACE_USBHOST(printf("ADK::Init getConf : ");)
|
||||
goto Fail;
|
||||
|
||||
FailSetConf:
|
||||
TRACE_USBHOST(printf("ADK::Init setConf : ");)
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
TRACE_USBHOST(printf("error code: %lu\r\n", rcode);)
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Extract bulk-IN and bulk-OUT endpoint information from configuration
|
||||
* descriptor.
|
||||
*
|
||||
* \param conf Configuration number.
|
||||
* \param iface Interface number.
|
||||
* \param alt Alternate setting.
|
||||
* \param proto Protocol version used.
|
||||
* \param pep Pointer to endpoint descriptor.
|
||||
*/
|
||||
void ADK::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
|
||||
{
|
||||
if (bNumEP == 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bConfNum = conf;
|
||||
|
||||
uint32_t index = 0;
|
||||
uint32_t pipe = 0;
|
||||
|
||||
if ((pep->bmAttributes & 0x02) == 2)
|
||||
{
|
||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
|
||||
}
|
||||
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].deviceEpNum = pep->bEndpointAddress & 0x0F;
|
||||
epInfo[index].maxPktSize = pep->wMaxPacketSize;
|
||||
|
||||
TRACE_USBHOST(printf("ADK::EndpointXtract : Found new endpoint\r\n");)
|
||||
TRACE_USBHOST(printf("ADK::EndpointXtract : deviceEpNum: %lu\r\n", epInfo[index].deviceEpNum);)
|
||||
TRACE_USBHOST(printf("ADK::EndpointXtract : maxPktSize: %lu\r\n", epInfo[index].maxPktSize);)
|
||||
TRACE_USBHOST(printf("ADK::EndpointXtract : index: %lu\r\n", index);)
|
||||
|
||||
if (index == epDataInIndex)
|
||||
pipe = UHD_Pipe_Alloc(bAddress, epInfo[index].deviceEpNum, UOTGHS_HSTPIPCFG_PTYPE_BLK, UOTGHS_HSTPIPCFG_PTOKEN_IN, epInfo[index].maxPktSize, 0, UOTGHS_HSTPIPCFG_PBK_1_BANK);
|
||||
else if (index == epDataOutIndex)
|
||||
pipe = UHD_Pipe_Alloc(bAddress, epInfo[index].deviceEpNum, UOTGHS_HSTPIPCFG_PTYPE_BLK, UOTGHS_HSTPIPCFG_PTOKEN_OUT, epInfo[index].maxPktSize, 0, UOTGHS_HSTPIPCFG_PBK_1_BANK);
|
||||
|
||||
// Ensure pipe allocation is okay
|
||||
if (pipe == 0)
|
||||
{
|
||||
TRACE_USBHOST(printf("ADK::EndpointXtract : Pipe allocation failure\r\n");)
|
||||
// Enumeration failed, so user should not perform write/read since isConnected will return false
|
||||
return;
|
||||
}
|
||||
|
||||
epInfo[index].hostPipeNum = pipe;
|
||||
|
||||
bNumEP++;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Release USB allocated resources (pipes and address).
|
||||
*
|
||||
* \note Release call is made from USBHost.task() on disconnection events.
|
||||
* \note Release call is made from Init() on enumeration failure.
|
||||
*
|
||||
* \return Always 0.
|
||||
*/
|
||||
uint32_t ADK::Release()
|
||||
{
|
||||
// Free allocated host pipes
|
||||
UHD_Pipe_Free(epInfo[epDataInIndex].hostPipeNum);
|
||||
UHD_Pipe_Free(epInfo[epDataOutIndex].hostPipeNum);
|
||||
|
||||
// Free allocated USB address
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
// Must have to be reset to 1
|
||||
bNumEP = 1;
|
||||
|
||||
bAddress = 0;
|
||||
ready = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Read from ADK.
|
||||
*
|
||||
* \param nreadbytes Return value containing the number of read bytes.
|
||||
* \param datalen Buffer length.
|
||||
* \param dataptr Buffer to store the incoming data.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t ADK::read(uint32_t *nreadbytes, uint32_t datalen, uint8_t *dataptr)
|
||||
{
|
||||
*nreadbytes = datalen;
|
||||
return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].deviceEpNum, nreadbytes, dataptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Write to ADK.
|
||||
*
|
||||
* \param datalen Amount of data to send. This parameter shall not exceed
|
||||
* dataptr length.
|
||||
* \param dataptr Buffer containing the data to be sent.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t ADK::write(uint32_t datalen, uint8_t *dataptr)
|
||||
{
|
||||
return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].deviceEpNum, datalen, dataptr);
|
||||
}
|
150
hardware/arduino/sam/system/USBHost/adk.h
Normal file
150
hardware/arduino/sam/system/USBHost/adk.h
Normal file
@ -0,0 +1,150 @@
|
||||
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Circuits At Home, LTD
|
||||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
|
||||
/* Google ADK interface support header */
|
||||
|
||||
#ifndef ADK_H_INCLUDED
|
||||
#define ADK_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
#include "hid.h"
|
||||
#include "Arduino.h"
|
||||
#include "confdescparser.h"
|
||||
|
||||
#define ADK_VID 0x18D1
|
||||
#define ADK_PID 0x2D00
|
||||
#define ADB_PID 0x2D01
|
||||
|
||||
#define XOOM //enables repeating getProto() and getConf() attempts
|
||||
//necessary for slow devices such as Motorola XOOM
|
||||
//defined by default, can be commented out to save memory
|
||||
|
||||
/* Requests */
|
||||
|
||||
#define ADK_GETPROTO 51 //check USB accessory protocol version
|
||||
#define ADK_SENDSTR 52 //send identifying string
|
||||
#define ADK_ACCSTART 53 //start device in accessory mode
|
||||
|
||||
#define bmREQ_ADK_GET USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
|
||||
#define bmREQ_ADK_SEND USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_VENDOR|USB_SETUP_RECIPIENT_DEVICE
|
||||
|
||||
#define ACCESSORY_STRING_MANUFACTURER 0
|
||||
#define ACCESSORY_STRING_MODEL 1
|
||||
#define ACCESSORY_STRING_DESCRIPTION 2
|
||||
#define ACCESSORY_STRING_VERSION 3
|
||||
#define ACCESSORY_STRING_URI 4
|
||||
#define ACCESSORY_STRING_SERIAL 5
|
||||
|
||||
#define ADK_MAX_ENDPOINTS 3 //endpoint 0, bulk_IN, bulk_OUT
|
||||
|
||||
/**
|
||||
* \class ADK definition.
|
||||
*/
|
||||
class ADK : public USBDeviceConfig, public UsbConfigXtracter
|
||||
{
|
||||
private:
|
||||
/* ID strings */
|
||||
const char* manufacturer;
|
||||
const char* model;
|
||||
const char* description;
|
||||
const char* version;
|
||||
const char* uri;
|
||||
const char* serial;
|
||||
|
||||
/* ADK proprietary requests */
|
||||
uint32_t getProto(uint8_t* adkproto);
|
||||
uint32_t sendStr(uint32_t index, const char* str);
|
||||
uint32_t switchAcc(void);
|
||||
|
||||
protected:
|
||||
static const uint32_t epDataInIndex; // DataIn endpoint index
|
||||
static const uint32_t epDataOutIndex; // DataOUT endpoint index
|
||||
|
||||
/* Mandatory members */
|
||||
USBHost *pUsb;
|
||||
uint32_t bAddress; // Device USB address
|
||||
uint32_t bConfNum; // configuration number
|
||||
|
||||
uint32_t bNumEP; // total number of EP in the configuration
|
||||
bool ready;
|
||||
|
||||
/* Endpoint data structure describing the device EP */
|
||||
EpInfo epInfo[ADK_MAX_ENDPOINTS];
|
||||
|
||||
public:
|
||||
ADK(USBHost *pUsb, const char* pmanufacturer,
|
||||
const char* pmodel,
|
||||
const char* pdescription,
|
||||
const char* pversion,
|
||||
const char* puri,
|
||||
const char* pserial);
|
||||
|
||||
// Methods for receiving and sending data
|
||||
uint32_t read(uint32_t *nreadbytes, uint32_t datalen, uint8_t *dataptr);
|
||||
uint32_t write(uint32_t datalen, uint8_t *dataptr);
|
||||
|
||||
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed);
|
||||
virtual uint32_t Release();
|
||||
virtual uint32_t Poll() { return 0; }; // not implemented
|
||||
virtual uint32_t GetAddress() { return bAddress; };
|
||||
virtual bool isReady() { return ready; };
|
||||
|
||||
// UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get ADK protocol version.
|
||||
*
|
||||
* \param adkproto Empty buffer to be filled by getProto (2 bytes) with the ADK
|
||||
* protocol version value.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
inline uint32_t ADK::getProto(uint8_t* adkproto)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_GET, ADK_GETPROTO, 0, 0, 0, 2, 2, adkproto, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Send ADK string.
|
||||
*
|
||||
* \param index String index.
|
||||
* \param str String to send.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
inline uint32_t ADK::sendStr(uint32_t index, const char* str)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_SENDSTR, 0, 0, index, strlen(str) + 1, strlen(str) + 1, (uint8_t*)str, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Send a switch to accessory mode request.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
inline uint32_t ADK::switchAcc(void)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_ADK_SEND, ADK_ACCSTART, 0, 0, 0, 0, 0, NULL, NULL));
|
||||
}
|
||||
|
||||
#endif /* ADK_H_INCLUDED */
|
@ -21,6 +21,11 @@ e-mail : support@circuitsathome.com
|
||||
#include <stdint.h>
|
||||
#include "parsetools.h"
|
||||
|
||||
/**
|
||||
* \class Abstract UsbConfigXtracter definition.
|
||||
*
|
||||
* \note This class is used for extracting USB endpoint descriptors.
|
||||
*/
|
||||
class UsbConfigXtracter
|
||||
{
|
||||
public:
|
||||
@ -32,7 +37,11 @@ public:
|
||||
#define CP_MASK_COMPARE_PROTOCOL 4
|
||||
#define CP_MASK_COMPARE_ALL 7
|
||||
|
||||
// Configuration Descriptor Parser Class Template
|
||||
/**
|
||||
* \class ConfigDescParser definition.
|
||||
*
|
||||
* \note This class is used for parsing configuration descriptors.
|
||||
*/
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
class ConfigDescParser : public USBReadParser
|
||||
{
|
||||
@ -62,6 +71,18 @@ public:
|
||||
virtual void Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ConfigDescParser class constructor.
|
||||
*
|
||||
* \param xtractor Is saved as ConfigDescParser attribute and later used as a
|
||||
* callback for parsing the endpoint descriptors.
|
||||
*
|
||||
* \note During enumeration stage, all supported USB classes invoke
|
||||
* ConfigDescParser with "this" as parameter, meaning that one class is also
|
||||
* responsible for parsing its endpoint descriptors. This makes sense since
|
||||
* each USB class handles different number of endpoints and configurations.
|
||||
* For instance see ADK::Init from ADK class.
|
||||
*/
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(UsbConfigXtracter *xtractor) :
|
||||
theXtractor(xtractor),
|
||||
@ -74,18 +95,37 @@ ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ConfigDescParser(Usb
|
||||
theSkipper.Initialize(&theBuffer);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Parse a complete USB configuration descriptor.
|
||||
*
|
||||
* \param len Buffer length.
|
||||
* \param pbuf Buffer containing the configuration descriptor.
|
||||
* \param offset Current offset position.
|
||||
*/
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset)
|
||||
{
|
||||
uint32_t cntdn = len;
|
||||
uint8_t *p = (uint8_t*)pbuf;
|
||||
|
||||
while(cntdn)
|
||||
while (cntdn)
|
||||
if (!ParseDescriptor(&p, &cntdn))
|
||||
return;
|
||||
}
|
||||
/* Parser for the configuration descriptor. Takes values for class, subclass, protocol fields in interface descriptor and
|
||||
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
|
||||
|
||||
/**
|
||||
* \brief Parse a USB configuration descriptor.
|
||||
* Takes values for class, subclass, protocol fields in interface descriptor
|
||||
* and compare masks for them. When the match is found, calls EndpointXtract
|
||||
* passing buffer containing endpoint descriptor.
|
||||
*
|
||||
* \note This method should not be called directly, use Parse() instead.
|
||||
*
|
||||
* \param pcntdn Buffer length.
|
||||
* \param pp Buffer containing the configuration descriptor.
|
||||
*
|
||||
* \return true if data remains in the buffer for parsing, false otherwise.
|
||||
*/
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint32_t *pcntdn)
|
||||
{
|
||||
@ -112,102 +152,90 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
|
||||
case 3:
|
||||
switch (dscrType)
|
||||
{
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
isGoodInterface = false;
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case HID_DESCRIPTOR_HID:
|
||||
theBuffer.valueSize = dscrLen - 2;
|
||||
break;
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
isGoodInterface = false;
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
theBuffer.valueSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
theBuffer.valueSize = sizeof(USB_ENDPOINT_DESCRIPTOR) - 2;
|
||||
break;
|
||||
case HID_DESCRIPTOR_HID:
|
||||
theBuffer.valueSize = dscrLen - 2;
|
||||
break;
|
||||
}
|
||||
valParser.Initialize(&theBuffer);
|
||||
stateParseDescr = 4;
|
||||
case 4:
|
||||
switch (dscrType)
|
||||
{
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue;
|
||||
break;
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID)
|
||||
break;
|
||||
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
|
||||
break;
|
||||
if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
|
||||
case USB_DESCRIPTOR_CONFIGURATION:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
confValue = ((USB_CONFIGURATION_DESCRIPTOR*)varBuffer)->bConfigurationValue;
|
||||
break;
|
||||
case USB_DESCRIPTOR_INTERFACE:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
if ((MASK & CP_MASK_COMPARE_CLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceClass != CLASS_ID)
|
||||
break;
|
||||
if ((MASK & CP_MASK_COMPARE_SUBCLASS) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceSubClass != SUBCLASS_ID)
|
||||
break;
|
||||
if ((MASK & CP_MASK_COMPARE_PROTOCOL) && ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol != PROTOCOL_ID)
|
||||
break;
|
||||
|
||||
isGoodInterface = true;
|
||||
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber;
|
||||
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting;
|
||||
protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
if (isGoodInterface)
|
||||
if (theXtractor)
|
||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
||||
break;
|
||||
//case HID_DESCRIPTOR_HID:
|
||||
// if (!valParser.Parse(pp, pcntdn))
|
||||
// return false;
|
||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||
// break;
|
||||
default:
|
||||
if (!theSkipper.Skip(pp, pcntdn, dscrLen-2))
|
||||
return false;
|
||||
}
|
||||
theBuffer.pValue = varBuffer;
|
||||
stateParseDescr = 0;
|
||||
isGoodInterface = true;
|
||||
ifaceNumber = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceNumber;
|
||||
ifaceAltSet = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bAlternateSetting;
|
||||
protoValue = ((USB_INTERFACE_DESCRIPTOR*)varBuffer)->bInterfaceProtocol;
|
||||
break;
|
||||
case USB_DESCRIPTOR_ENDPOINT:
|
||||
if (!valParser.Parse(pp, pcntdn))
|
||||
return false;
|
||||
if (isGoodInterface)
|
||||
if (theXtractor)
|
||||
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
|
||||
break;
|
||||
//case HID_DESCRIPTOR_HID:
|
||||
// if (!valParser.Parse(pp, pcntdn))
|
||||
// return false;
|
||||
// PrintHidDescriptor((const USB_HID_DESCRIPTOR*)varBuffer);
|
||||
// break;
|
||||
default:
|
||||
if (!theSkipper.Skip(pp, pcntdn, dscrLen - 2))
|
||||
return false;
|
||||
}
|
||||
theBuffer.pValue = varBuffer;
|
||||
stateParseDescr = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Print HID descriptor.
|
||||
*
|
||||
* \note TRACE_USBHOST macro must be enabled. See Usb.h for reference.
|
||||
*
|
||||
* \param pDesc Pointer to HID descriptor.
|
||||
*/
|
||||
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
|
||||
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
||||
{
|
||||
/*Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
|
||||
Notify(PSTR("bDescLength:\t\t"));
|
||||
PrintHex<uint8_t>(pDesc->bLength);
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescLength: %d\r\n", pDesc->bLength);)
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescriptorType: %d\r\n", pDesc->bDescriptorType);)
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bcdHID: %d\r\n", pDesc->bcdHID);)
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bCountryCode: %d\r\n", pDesc->bCountryCode);)
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bNumDescriptors: %d\r\n", pDesc->bNumDescriptors);)
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescrType: %d\r\n", pDesc->bDescrType);)
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : wDescriptorLength: %d\r\n", pDesc->wDescriptorLength);)
|
||||
|
||||
Notify(PSTR("\r\nbDescriptorType:\t"));
|
||||
PrintHex<uint8_t>(pDesc->bDescriptorType);
|
||||
|
||||
Notify(PSTR("\r\nbcdHID:\t\t\t"));
|
||||
PrintHex<uint16_t>(pDesc->bcdHID);
|
||||
|
||||
Notify(PSTR("\r\nbCountryCode:\t\t"));
|
||||
PrintHex<uint8_t>(pDesc->bCountryCode);
|
||||
|
||||
Notify(PSTR("\r\nbNumDescriptors:\t"));
|
||||
PrintHex<uint8_t>(pDesc->bNumDescriptors);
|
||||
|
||||
//Notify(PSTR("\r\nbDescrType:\t\t"));
|
||||
//PrintHex<uint8_t>(pDesc->bDescrType);
|
||||
//
|
||||
//Notify(PSTR("\r\nwDescriptorLength:\t"));
|
||||
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
|
||||
|
||||
for (uint8_t i=0; i<pDesc->bNumDescriptors; i++)
|
||||
for (uint32_t i = 0; i < pDesc->bNumDescriptors; ++i)
|
||||
{
|
||||
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
|
||||
|
||||
Notify(PSTR("\r\nbDescrType:\t\t"));
|
||||
PrintHex<uint8_t>(pLT[i].bDescrType);
|
||||
|
||||
Notify(PSTR("\r\nwDescriptorLength:\t"));
|
||||
PrintHex<uint16_t>(pLT[i].wDescriptorLength);
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : bDescrType: %d\r\n", pLT[i].bDescrType);)
|
||||
TRACE_USBHOST(printf("ConfigDescParser::PrintHidDescriptor : wDescriptorLength: %d\r\n", pLT[i].wDescriptorLength);)
|
||||
}
|
||||
Notify(PSTR("\r\n"));*/
|
||||
printf("somebody save me!!!! orgazmo?!!!\r\n");
|
||||
}
|
||||
|
||||
#endif /* CONFDESCPARSER_H_INCLUDED */
|
||||
|
@ -0,0 +1,54 @@
|
||||
#include "variant.h"
|
||||
#include <stdio.h>
|
||||
#include <adk.h>
|
||||
|
||||
// Accessory descriptor. It's how Arduino identifies itself to Android.
|
||||
char applicationName[] = "Arduino_Terminal"; // the app on your phone
|
||||
char accessoryName[] = "Arduino Due X"; // your Arduino board
|
||||
char companyName[] = "Arduino SA";
|
||||
|
||||
// Make up anything you want for these
|
||||
char versionNumber[] = "1.0";
|
||||
char serialNumber[] = "1";
|
||||
char url[] = "http://labs.arduino.cc/uploads/ADK/ArduinoTerminal/ThibaultTerminal_ICS_0001.apk";
|
||||
|
||||
USBHost Usb;
|
||||
ADK adk(&Usb, companyName, applicationName, accessoryName,versionNumber,url,serialNumber);
|
||||
|
||||
void setup()
|
||||
{
|
||||
cpu_irq_enable();
|
||||
printf("\r\nADK demo start\r\n");
|
||||
delay(200);
|
||||
}
|
||||
|
||||
#define RCVSIZE 128
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t buf[RCVSIZE];
|
||||
uint32_t nbread = 0;
|
||||
char helloworld[] = "Hello World!\r\n";
|
||||
|
||||
Usb.Task();
|
||||
|
||||
if (adk.isReady())
|
||||
{
|
||||
/* Write hello string to ADK */
|
||||
adk.write(strlen(helloworld), (uint8_t *)helloworld);
|
||||
|
||||
delay(1000);
|
||||
|
||||
/* Read data from ADK and print to UART */
|
||||
adk.read(&nbread, RCVSIZE, buf);
|
||||
if (nbread > 0)
|
||||
{
|
||||
printf("RCV: ");
|
||||
for (uint32_t i = 0; i < nbread; ++i)
|
||||
{
|
||||
printf("%c", (char)buf[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
@ -95,7 +95,10 @@ e-mail : support@circuitsathome.com
|
||||
#define HID_PROTOCOL_KEYBOARD 0x01
|
||||
#define HID_PROTOCOL_MOUSE 0x02
|
||||
|
||||
struct HidItemPrefix
|
||||
/**
|
||||
* \brief HidItemPrefix definition.
|
||||
*/
|
||||
struct HidItemPrefix // Not used
|
||||
{
|
||||
uint8_t bSize : 2;
|
||||
uint8_t bType : 2;
|
||||
@ -125,7 +128,10 @@ struct HidItemPrefix
|
||||
#define HID_MAIN_ITEM_COLLECTION_USAGE_SWITCH 5
|
||||
#define HID_MAIN_ITEM_COLLECTION_USAGE_MODIFIER 6
|
||||
|
||||
struct MainItemIOFeature
|
||||
/**
|
||||
* \brief MainItemIOFeature definition.
|
||||
*/
|
||||
struct MainItemIOFeature // Not used
|
||||
{
|
||||
uint8_t bmIsConstantOrData : 1;
|
||||
uint8_t bmIsArrayOrVariable : 1;
|
||||
@ -139,6 +145,11 @@ struct MainItemIOFeature
|
||||
|
||||
class HID;
|
||||
|
||||
/**
|
||||
* \class Abstract HIDReportParser definition.
|
||||
*
|
||||
* \note This class is used to implement HID report parsing.
|
||||
*/
|
||||
class HIDReportParser
|
||||
{
|
||||
public:
|
||||
@ -148,6 +159,9 @@ public:
|
||||
#define MAX_REPORT_PARSERS 2
|
||||
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
||||
|
||||
/**
|
||||
* \class HID definition.
|
||||
*/
|
||||
class HID : public USBDeviceConfig, public UsbConfigXtracter
|
||||
{
|
||||
protected:
|
||||
|
@ -17,7 +17,14 @@ e-mail : support@circuitsathome.com
|
||||
|
||||
#include "hid.h"
|
||||
|
||||
// Get HID report descriptor
|
||||
/**
|
||||
* \brief Get HID report descriptor and parse it.
|
||||
*
|
||||
* \param ep USB device endpoint.
|
||||
* \param parser Parser used to decode report.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t HID::GetReportDescr(uint32_t ep, USBReadParser *parser)
|
||||
{
|
||||
const uint32_t constBufLen = 64;
|
||||
@ -27,75 +34,108 @@ uint32_t HID::GetReportDescr(uint32_t ep, USBReadParser *parser)
|
||||
HID_DESCRIPTOR_REPORT, 0x0000, 128, constBufLen, buf, (USBReadParser*)parser));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Set HID report descriptor.
|
||||
*
|
||||
* \param ep USB device endpoint.
|
||||
* \param iface Interface number.
|
||||
* \param report_type HID report type.
|
||||
* \param report_id HID report ID.
|
||||
* \param nbytes Buffer length.
|
||||
* \param dataptr Buffer containing the HID report to send.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t HID::SetReport(uint32_t ep, uint32_t iface, uint32_t report_type, uint32_t report_id, uint32_t nbytes, uint8_t* dataptr)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get HID report descriptor.
|
||||
*
|
||||
* \param ep USB device endpoint.
|
||||
* \param iface Interface number.
|
||||
* \param report_type HID report type.
|
||||
* \param report_id HID report ID.
|
||||
* \param nbytes Buffer length.
|
||||
* \param dataptr Buffer containing the HID report to send.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t HID::GetReport(uint32_t ep, uint32_t iface, uint32_t report_type, uint32_t report_id, uint32_t nbytes, uint8_t* dataptr)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, iface, nbytes, nbytes, dataptr, NULL));
|
||||
}
|
||||
|
||||
uint32_t HID::GetIdle(uint32_t iface, uint32_t reportID, uint8_t* dataptr)
|
||||
/**
|
||||
* \brief Get HID idle status.
|
||||
*
|
||||
* \param iface Interface number.
|
||||
* \param report_id HID report ID.
|
||||
* \param dataptr Buffer to receive data. Size must be >= 1.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t HID::GetIdle(uint32_t iface, uint32_t report_id, uint8_t* dataptr)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, iface, 0x0001, 0x0001, dataptr, NULL));
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, report_id, 0, iface, 0x0001, 0x0001, dataptr, NULL));
|
||||
}
|
||||
|
||||
uint32_t HID::SetIdle(uint32_t iface, uint32_t reportID, uint32_t duration)
|
||||
/**
|
||||
* \brief Set HID idle status.
|
||||
*
|
||||
* \param iface Interface number.
|
||||
* \param report_id HID report ID.
|
||||
* \param duration Status duration.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t HID::SetIdle(uint32_t iface, uint32_t report_id, uint32_t duration)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, iface, 0x0000, 0x0000, NULL, NULL));
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, report_id, duration, iface, 0x0000, 0x0000, NULL, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set HID protocol.
|
||||
*
|
||||
* \param iface Interface number.
|
||||
* \param protocol Protocol value.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t HID::SetProtocol(uint32_t iface, uint32_t protocol)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, iface, 0x0000, 0x0000, NULL, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get HID protocol.
|
||||
*
|
||||
* \param iface Interface number.
|
||||
* \param dataptr Buffer used to store protocol value. Size must be >= 1.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint32_t HID::GetProtocol(uint32_t iface, uint8_t* dataptr)
|
||||
{
|
||||
return (pUsb->ctrlReq(bAddress, 0, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, iface, 0x0001, 0x0001, dataptr, NULL));
|
||||
}
|
||||
|
||||
void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr)
|
||||
{
|
||||
/*Notify(PSTR("Endpoint descriptor:"));
|
||||
Notify(PSTR("\r\nLength:\t\t"));
|
||||
PrintHex<uint8_t>(ep_ptr->bLength);
|
||||
Notify(PSTR("\r\nType:\t\t"));
|
||||
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
|
||||
Notify(PSTR("\r\nAddress:\t"));
|
||||
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
|
||||
Notify(PSTR("\r\nAttributes:\t"));
|
||||
PrintHex<uint8_t>(ep_ptr->bmAttributes);
|
||||
Notify(PSTR("\r\nMaxPktSize:\t"));
|
||||
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
|
||||
Notify(PSTR("\r\nPoll Intrv:\t"));
|
||||
PrintHex<uint8_t>(ep_ptr->bInterval);*/
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Print HID descriptor.
|
||||
*
|
||||
* \note TRACE_USBHOST macro must be enabled. See Usb.h for reference.
|
||||
*
|
||||
* \param pDesc Pointer to HID descriptor.
|
||||
*/
|
||||
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc)
|
||||
{
|
||||
/* Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"));
|
||||
Notify(PSTR("bDescLength:\t\t"));
|
||||
PrintHex<uint8_t>(pDesc->bLength);
|
||||
|
||||
Notify(PSTR("\r\nbDescriptorType:\t"));
|
||||
PrintHex<uint8_t>(pDesc->bDescriptorType);
|
||||
|
||||
Notify(PSTR("\r\nbcdHID:\t\t\t"));
|
||||
PrintHex<uint16_t>(pDesc->bcdHID);
|
||||
|
||||
Notify(PSTR("\r\nbCountryCode:\t\t"));
|
||||
PrintHex<uint8_t>(pDesc->bCountryCode);
|
||||
|
||||
Notify(PSTR("\r\nbNumDescriptors:\t"));
|
||||
PrintHex<uint8_t>(pDesc->bNumDescriptors);
|
||||
|
||||
Notify(PSTR("\r\nbDescrType:\t\t"));
|
||||
PrintHex<uint8_t>(pDesc->bDescrType);
|
||||
|
||||
Notify(PSTR("\r\nwDescriptorLength:\t"));
|
||||
PrintHex<uint16_t>(pDesc->wDescriptorLength);*/
|
||||
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescLength: %d\r\n", pDesc->bLength);)
|
||||
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescriptorType: %d\r\n", pDesc->bDescriptorType);)
|
||||
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bcdHID: %d\r\n", pDesc->bcdHID);)
|
||||
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bCountryCode: %d\r\n", pDesc->bCountryCode);)
|
||||
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bNumDescriptors: %d\r\n", pDesc->bNumDescriptors);)
|
||||
TRACE_USBHOST(printf("HID::PrintHidDescriptor : bDescrType: %d\r\n", pDesc->bDescrType);)
|
||||
TRACE_USBHOST(printf("HID::PrintHidDescriptor : wDescriptorLength: %d\r\n", pDesc->wDescriptorLength);)
|
||||
}
|
||||
|
@ -17,6 +17,14 @@ e-mail : support@circuitsathome.com
|
||||
|
||||
#include "hidboot.h"
|
||||
|
||||
/**
|
||||
* \brief Parse HID mouse report.
|
||||
*
|
||||
* \param hid HID device pointer.
|
||||
* \param is_rpt_id True if this is a report ID.
|
||||
* \param len Buffer length.
|
||||
* \param buf Buffer containing report data.
|
||||
*/
|
||||
void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *buf)
|
||||
{
|
||||
MOUSEINFO *pmi = (MOUSEINFO*)buf;
|
||||
@ -46,6 +54,14 @@ void MouseReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *b
|
||||
prevState.bInfo[i] = buf[i];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Parse HID keyboard report.
|
||||
*
|
||||
* \param hid HID device pointer.
|
||||
* \param is_rpt_id True if this is a report ID.
|
||||
* \param len Buffer length.
|
||||
* \param buf Buffer containing report data.
|
||||
*/
|
||||
void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t *buf)
|
||||
{
|
||||
// On error - return
|
||||
@ -81,6 +97,15 @@ void KeyboardReportParser::Parse(HID *hid, bool is_rpt_id, uint32_t len, uint8_t
|
||||
prevState.bInfo[i] = buf[i];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Handle keyboard locking keys and manage keyboard leds using USB
|
||||
* report.
|
||||
*
|
||||
* \param hid HID device pointer.
|
||||
* \param key Locking key.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
uint8_t KeyboardReportParser::HandleLockingKeys(HID *hid, uint8_t key)
|
||||
{
|
||||
uint8_t old_keys = kbdLockingKeys.bLeds;
|
||||
@ -109,6 +134,14 @@ const uint8_t KeyboardReportParser::symKeysUp[] = { '_', '+', '{', '}', '|', '~'
|
||||
const uint8_t KeyboardReportParser::symKeysLo[] = { '-', '=', '[', ']', '\\', ' ', ';', '\'', '`', ',', '.', '/' };
|
||||
const uint8_t KeyboardReportParser::padKeys[] = { '/', '*', '-', '+', 0x13 };
|
||||
|
||||
/**
|
||||
* \brief Manage keyboard OEM to ASCII conversion.
|
||||
*
|
||||
* \param mod Keyboard modifier.
|
||||
* \param key Key value to convert.
|
||||
*
|
||||
* \return Keyboard corresponding ASCII value on success, 0 otherwise.
|
||||
*/
|
||||
uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key)
|
||||
{
|
||||
uint8_t shift = (mod & 0x22);
|
||||
@ -154,5 +187,6 @@ uint8_t KeyboardReportParser::OemToAscii(uint8_t mod, uint8_t key)
|
||||
case KEY_PERIOD: return ((kbdLockingKeys.kbdLeds.bmNumLock == 1) ? '.' : 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ e-mail : support@circuitsathome.com
|
||||
#define KEY_ENTER 0x28
|
||||
#define KEY_PERIOD 0x63
|
||||
|
||||
/**
|
||||
* \brief MOUSEINFO definition.
|
||||
*/
|
||||
struct MOUSEINFO
|
||||
{
|
||||
struct
|
||||
@ -44,6 +47,9 @@ struct MOUSEINFO
|
||||
int8_t dY;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class MouseReportParser definition.
|
||||
*/
|
||||
class MouseReportParser : public HIDReportParser
|
||||
{
|
||||
union
|
||||
@ -65,6 +71,9 @@ protected:
|
||||
virtual void OnMiddleButtonDown (MOUSEINFO *mi) {};
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief MODIFIERKEYS definition.
|
||||
*/
|
||||
struct MODIFIERKEYS
|
||||
{
|
||||
uint8_t bmLeftCtrl : 1;
|
||||
@ -77,6 +86,9 @@ struct MODIFIERKEYS
|
||||
uint8_t bmRightGUI : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief KBDINFO definition.
|
||||
*/
|
||||
struct KBDINFO
|
||||
{
|
||||
struct
|
||||
@ -94,6 +106,9 @@ struct KBDINFO
|
||||
uint8_t Keys[6];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief KBDLEDS definition.
|
||||
*/
|
||||
struct KBDLEDS
|
||||
{
|
||||
uint8_t bmNumLock : 1;
|
||||
@ -105,9 +120,18 @@ struct KBDLEDS
|
||||
};
|
||||
|
||||
#define KEY_NUM_LOCK 0x53
|
||||
|
||||
// Clear compiler warning
|
||||
#ifdef KEY_CAPS_LOCK
|
||||
#undef KEY_CAPS_LOCK
|
||||
#endif
|
||||
|
||||
#define KEY_CAPS_LOCK 0x39
|
||||
#define KEY_SCROLL_LOCK 0x47
|
||||
|
||||
/**
|
||||
* \class KeyboardReportParser definition.
|
||||
*/
|
||||
class KeyboardReportParser : public HIDReportParser
|
||||
{
|
||||
static const uint8_t numKeys[];
|
||||
@ -146,6 +170,9 @@ protected:
|
||||
|
||||
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
||||
|
||||
/**
|
||||
* \class HIDBoot definition.
|
||||
*/
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
class HIDBoot : public HID
|
||||
{
|
||||
@ -167,7 +194,7 @@ class HIDBoot : public HID
|
||||
public:
|
||||
HIDBoot(USBHost *p);
|
||||
|
||||
virtual bool SetReportParser(uint32_t id, HIDReportParser *prs) { pRptParser = prs; return true;}; /////////////////////// le return ne sert a rien ?!!!
|
||||
virtual bool SetReportParser(uint32_t id, HIDReportParser *prs) { pRptParser = prs; return true; };
|
||||
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint32_t Init(uint32_t parent, uint32_t port, uint32_t lowspeed);
|
||||
@ -179,6 +206,9 @@ public:
|
||||
virtual void EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief HIDBoot class constructor.
|
||||
*/
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USBHost *p) :
|
||||
HID(p),
|
||||
@ -192,21 +222,35 @@ HIDBoot<BOOT_PROTOCOL>::HIDBoot(USBHost *p) :
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize HIDBoot class.
|
||||
*/
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
void HIDBoot<BOOT_PROTOCOL>::Initialize()
|
||||
{
|
||||
for(uint32_t i = 0; i < totalEndpoints; ++i)
|
||||
for (uint32_t i = 0; i < totalEndpoints; ++i)
|
||||
{
|
||||
epInfo[i].epAddr = 0;
|
||||
epInfo[i].deviceEpNum = 0;
|
||||
epInfo[i].hostPipeNum = 0;
|
||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||
epInfo[i].epAttribs = 0;
|
||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||
}
|
||||
|
||||
bNumEP = 1;
|
||||
bNumIface = 0;
|
||||
bConfNum = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize connection to an HID device.
|
||||
*
|
||||
* \param parent USB device address of the Parent device.
|
||||
* \param port USB device base address.
|
||||
* \param lowspeed USB device speed.
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t lowspeed)
|
||||
{
|
||||
@ -214,14 +258,16 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
||||
|
||||
uint8_t buf[constBufSize];
|
||||
uint32_t rcode = 0;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
UsbDevice *p = 0;
|
||||
EpInfo *oldep_ptr = 0;
|
||||
uint32_t len = 0;
|
||||
|
||||
uint32_t num_of_conf; // number of configurations
|
||||
uint32_t num_of_conf = 0; // number of configurations
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
TRACE_USBHOST(printf("HIDBoot::Init\r\n");)
|
||||
|
||||
if (bAddress)
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
||||
@ -246,9 +292,9 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr( 0, 0, 8, (uint8_t*)buf );
|
||||
rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
|
||||
|
||||
if (!rcode)
|
||||
if (!rcode)
|
||||
len = (buf[0] > constBufSize) ? constBufSize : buf[0];
|
||||
|
||||
if (rcode)
|
||||
@ -312,14 +358,12 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
||||
|
||||
for (uint32_t i = 0; i < num_of_conf; ++i)
|
||||
{
|
||||
//HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
|
||||
ConfigDescParser<
|
||||
USB_CLASS_HID,
|
||||
HID_BOOT_INTF_SUBCLASS,
|
||||
BOOT_PROTOCOL,
|
||||
CP_MASK_COMPARE_ALL> confDescrParser(this);
|
||||
CP_MASK_COMPARE_ALL> confDescrParser(this);
|
||||
|
||||
//rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
|
||||
if (bNumEP > 1)
|
||||
@ -364,31 +408,41 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Init(uint32_t parent, uint32_t port, uint32_t l
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
//USBTRACE("getDevDescr:");
|
||||
TRACE_USBHOST(printf("HIDBoot::Init getDevDescr : ");)
|
||||
goto Fail;
|
||||
|
||||
FailSetDevTblEntry:
|
||||
//USBTRACE("setDevTblEn:");
|
||||
TRACE_USBHOST(printf("HIDBoot::Init setDevTblEn : ");)
|
||||
goto Fail;
|
||||
|
||||
FailSetProtocol:
|
||||
//USBTRACE("SetProto:");
|
||||
TRACE_USBHOST(printf("HIDBoot::Init SetProto : ");)
|
||||
goto Fail;
|
||||
|
||||
FailSetIdle:
|
||||
//USBTRACE("SetIdle:");
|
||||
TRACE_USBHOST(printf("HIDBoot::Init SetIdle : ");)
|
||||
goto Fail;
|
||||
|
||||
FailSetConfDescr:
|
||||
//USBTRACE("setConf:");
|
||||
TRACE_USBHOST(printf("HIDBoot::Init setConf : ");)
|
||||
goto Fail;
|
||||
|
||||
Fail:
|
||||
//Serial.println(rcode, HEX);
|
||||
TRACE_USBHOST(printf("error code: %lu\r\n", rcode);)
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Extract interrupt-IN endpoint information from configuration
|
||||
* descriptor.
|
||||
*
|
||||
* \param conf Configuration number.
|
||||
* \param iface Interface number.
|
||||
* \param alt Alternate setting.
|
||||
* \param proto Protocol version used.
|
||||
* \param pep Pointer to endpoint descriptor.
|
||||
*/
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint32_t conf, uint32_t iface, uint32_t alt, uint32_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
|
||||
{
|
||||
@ -396,41 +450,56 @@ void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint32_t conf, uint32_t iface, uint3
|
||||
if (bNumEP > 1 && conf != bConfNum)
|
||||
return;
|
||||
|
||||
//ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
|
||||
//ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
|
||||
//ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
|
||||
bConfNum = conf;
|
||||
bIfaceNum = iface;
|
||||
|
||||
bConfNum = conf;
|
||||
bIfaceNum = iface;
|
||||
|
||||
uint32_t index;
|
||||
uint32_t index = 0;
|
||||
uint32_t pipe = 0;
|
||||
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
|
||||
{
|
||||
index = epInterruptInIndex;
|
||||
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].deviceEpNum = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
|
||||
epInfo[index].epAttribs = 0;
|
||||
|
||||
bNumEP++;
|
||||
|
||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : Found new endpoint\r\n");)
|
||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : epAddr: %lu\r\n", epInfo[index].epAddr);)
|
||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : deviceEpNum: %lu\r\n", epInfo[index].deviceEpNum);)
|
||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : maxPktSize: %lu\r\n", epInfo[index].maxPktSize);)
|
||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : index: %lu\r\n", index);)
|
||||
|
||||
UHD_EP_Alloc(epInfo[index].epAddr, bAddress, 10, UOTGHS_HSTPIPCFG_PTYPE_INTRPT, UOTGHS_HSTPIPCFG_PTOKEN_IN, epInfo[index].maxPktSize, UOTGHS_HSTPIPCFG_PBK_1_BANK);
|
||||
// Ensure pipe allocation is okay
|
||||
pipe = UHD_Pipe_Alloc(bAddress, epInfo[index].deviceEpNum, UOTGHS_HSTPIPCFG_PTYPE_INTRPT, UOTGHS_HSTPIPCFG_PTOKEN_IN, epInfo[index].maxPktSize, 10, UOTGHS_HSTPIPCFG_PBK_1_BANK);
|
||||
if (pipe == 0)
|
||||
{
|
||||
TRACE_USBHOST(printf("HIDBoot::EndpointXtract : Pipe allocation failure\r\n");)
|
||||
// Enumeration failed
|
||||
return;
|
||||
}
|
||||
|
||||
//PrintEndpointDescriptor(pep);
|
||||
epInfo[index].hostPipeNum = pipe;
|
||||
|
||||
bNumEP++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Release USB allocated resources (pipes and address).
|
||||
*
|
||||
* \note Release call is made from USBHost.task() on disconnection events.
|
||||
* \note Release call is made from Init() on enumeration failure.
|
||||
*
|
||||
* \return Always 0.
|
||||
*/
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
uint32_t HIDBoot<BOOT_PROTOCOL>::Release()
|
||||
{
|
||||
// Free allocated host pipes
|
||||
UHD_Pipe_Free(epInfo[epInterruptInIndex].hostPipeNum);
|
||||
|
||||
// Free allocated USB address
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
|
||||
bConfNum = 0;
|
||||
@ -439,9 +508,17 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Release()
|
||||
bAddress = 0;
|
||||
qNextPollTime = 0;
|
||||
bPollEnable = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Poll USB device activity.
|
||||
*
|
||||
* \note Poll call is periodically made from USBHost.task().
|
||||
*
|
||||
* \return 0 on success, error code otherwise.
|
||||
*/
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
uint32_t HIDBoot<BOOT_PROTOCOL>::Poll()
|
||||
{
|
||||
@ -459,12 +536,10 @@ uint32_t HIDBoot<BOOT_PROTOCOL>::Poll()
|
||||
|
||||
uint32_t read = epInfo[epInterruptInIndex].maxPktSize;
|
||||
|
||||
rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||
rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].deviceEpNum, &read, buf);
|
||||
|
||||
if (rcode)
|
||||
{
|
||||
//if (rcode != hrNAK)
|
||||
//USBTRACE2("Poll:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,7 @@ e-mail : support@circuitsathome.com
|
||||
#define USB_FEATURE_ENDPOINT_STALL 0 // Endpoint recipient
|
||||
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 // Device recipient
|
||||
#define USB_FEATURE_TEST_MODE 2 // Device recipient
|
||||
|
||||
_Pragma("pack(1)")
|
||||
|
||||
/* descriptor data structures */
|
||||
@ -147,7 +148,7 @@ typedef struct
|
||||
uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
|
||||
uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
|
||||
uint8_t bmAttributes; // Endpoint transfer type.
|
||||
uint16_t wMaxPacketSize; // Maximum packet size.
|
||||
uint16_t wMaxPacketSize; // Maximum packet size.
|
||||
uint8_t bInterval; // Polling interval in frames.
|
||||
} USB_ENDPOINT_DESCRIPTOR;
|
||||
|
||||
|
@ -55,17 +55,16 @@ typedef enum {
|
||||
|
||||
//extern uhd_speed_t uhd_get_speed(void);
|
||||
|
||||
|
||||
extern void UHD_SetStack(void (*pf_isr)(void));
|
||||
extern void UHD_Init(void);
|
||||
extern void UHD_BusReset(void);
|
||||
extern uhd_vbus_state_t UHD_GetVBUSState(void);
|
||||
extern uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size);
|
||||
extern uint32_t UHD_EP_Alloc(uint32_t ul_pipe, uint32_t ul_addr, uint32_t ul_interval, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_bank);
|
||||
extern void UHD_EP_Free(uint32_t add, uint32_t endp);
|
||||
extern uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data);
|
||||
extern void UHD_EP_Write(uint32_t ul_ep, uint32_t ul_size, uint8_t* data);
|
||||
extern void UHD_EP_Send(uint32_t ul_ep, uint32_t ul_token_type);
|
||||
extern uint32_t UHD_EP_Is_Transfer_Complete(uint32_t ul_ep, uint32_t ul_token_type);
|
||||
extern uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size);
|
||||
extern uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_interval, uint32_t ul_nb_bank);
|
||||
extern void UHD_Pipe_Free(uint32_t ul_pipe);
|
||||
extern uint32_t UHD_Pipe_Read(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data);
|
||||
extern void UHD_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data);
|
||||
extern void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type);
|
||||
extern uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type);
|
||||
|
||||
#endif /* USB_HOST_H_INCLUDED */
|
||||
|
@ -32,13 +32,17 @@
|
||||
|
||||
#if SAM3XA_SERIES
|
||||
|
||||
#define TRACE_UOTGHS_HOST(x) x
|
||||
//#define TRACE_UOTGHS_HOST(x)
|
||||
//#define TRACE_UOTGHS_HOST(x) x
|
||||
#define TRACE_UOTGHS_HOST(x)
|
||||
|
||||
extern void (*gpf_isr)(void);
|
||||
|
||||
// Handle UOTGHS Host driver state
|
||||
static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS;
|
||||
|
||||
/**
|
||||
* \brief Interrupt sub routine for USB Host state machine management.
|
||||
*/
|
||||
static void UHD_ISR(void)
|
||||
{
|
||||
// Manage dis/connection event
|
||||
@ -74,7 +78,7 @@ static void UHD_ISR(void)
|
||||
{
|
||||
TRACE_UOTGHS_HOST(printf(">>> UHD_ISR : VBUS error INT\r\n");)
|
||||
uhd_ack_vbus_error_interrupt();
|
||||
uhd_state = UHD_STATE_ERROR;
|
||||
uhd_state = UHD_STATE_DISCONNECTED; //UHD_STATE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -111,11 +115,19 @@ static void UHD_ISR(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the interrupt sub routines callback for USB interrupts.
|
||||
*
|
||||
* \param pf_isr the ISR address.
|
||||
*/
|
||||
void UHD_SetStack(void (*pf_isr)(void))
|
||||
{
|
||||
gpf_isr = pf_isr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize the UOTGHS host driver.
|
||||
*/
|
||||
void UHD_Init(void)
|
||||
{
|
||||
irqflags_t flags;
|
||||
@ -178,7 +190,7 @@ void UHD_Init(void)
|
||||
|
||||
// Enable main control interrupt
|
||||
// Connection, SOF and reset
|
||||
UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTICR_DCONNIC;// | UOTGHS_HSTICR_RSTIC;// | UOTGHS_HSTICR_HSOFIC;
|
||||
UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTICR_DCONNIC;
|
||||
|
||||
otg_freeze_clock();
|
||||
|
||||
@ -187,11 +199,19 @@ void UHD_Init(void)
|
||||
cpu_irq_restore(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Trigger a USB bus reset.
|
||||
*/
|
||||
void UHD_BusReset(void)
|
||||
{
|
||||
uhd_start_reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get VBUS state.
|
||||
*
|
||||
* \return VBUS status.
|
||||
*/
|
||||
uhd_vbus_state_t UHD_GetVBUSState(void)
|
||||
{
|
||||
return uhd_state;
|
||||
@ -224,7 +244,7 @@ uhd_vbus_state_t UHD_GetVBUSState(void)
|
||||
* \retval 0 success.
|
||||
* \retval 1 error.
|
||||
*/
|
||||
uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size)
|
||||
uint32_t UHD_Pipe0_Alloc(uint32_t ul_add, uint32_t ul_ep_size)
|
||||
{
|
||||
if (ul_ep_size < 8)
|
||||
{
|
||||
@ -262,88 +282,88 @@ uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size)
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate FIFO for the specified pipe.
|
||||
* \brief Allocate a new pipe.
|
||||
*
|
||||
* \param ul_add Address of remote device for pipe 0.
|
||||
* \param ul_ep_size Actual size of the FIFO in bytes.
|
||||
* \note UOTGHS maximum pipe number is limited to 10, meaning that only a limited
|
||||
* amount of devices can be connected. Unfortunately, using only one pipe shared accross
|
||||
* various endpoints and devices is not possible because the UOTGHS IP does not allow to
|
||||
* change the data toggle value through register interface.
|
||||
*
|
||||
* \retval 0 success.
|
||||
* \retval 1 error.
|
||||
* \param ul_dev_addr Address of remote device.
|
||||
* \param ul_dev_ep Targeted endpoint of remote device.
|
||||
* \param ul_type Pipe type.
|
||||
* \param ul_dir Pipe direction.
|
||||
* \param ul_maxsize Pipe size.
|
||||
* \param ul_interval Polling interval (if applicable to pipe type).
|
||||
* \param ul_nb_bank Number of banks associated with this pipe.
|
||||
*
|
||||
* \return the newly allocated pipe number on success, 0 otherwise.
|
||||
*/
|
||||
uint32_t UHD_EP_Alloc(uint32_t ul_pipe, uint32_t ul_addr, uint32_t ul_interval, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_bank)
|
||||
uint32_t UHD_Pipe_Alloc(uint32_t ul_dev_addr, uint32_t ul_dev_ep, uint32_t ul_type, uint32_t ul_dir, uint32_t ul_maxsize, uint32_t ul_interval, uint32_t ul_nb_bank)
|
||||
{
|
||||
uint32_t ul_pipe = 1;
|
||||
|
||||
/*
|
||||
* Warning: this is a first implementation, pipe allocation is very limited.
|
||||
* We should probably check maxsize and if maxsize > current size, then realloc with maxsize.
|
||||
* If pipe type is changed, a pipe reset and re-configuration is required.
|
||||
*/
|
||||
|
||||
if (Is_uhd_pipe_enabled(ul_pipe))
|
||||
for (ul_pipe = 1; ul_pipe < UOTGHS_EPT_NUM; ++ul_pipe)
|
||||
{
|
||||
// Pipe is already allocated
|
||||
return 0;
|
||||
if (Is_uhd_pipe_enabled(ul_pipe))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uhd_enable_pipe(ul_pipe);
|
||||
|
||||
uhd_configure_pipe(ul_pipe, ul_interval, ul_dev_ep, ul_type, ul_dir,
|
||||
ul_maxsize, ul_nb_bank, UOTGHS_HSTPIPCFG_AUTOSW);
|
||||
|
||||
uhd_allocate_memory(ul_pipe);
|
||||
|
||||
if (!Is_uhd_pipe_configured(ul_pipe))
|
||||
{
|
||||
uhd_disable_pipe(ul_pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uhd_configure_address(ul_pipe, ul_dev_addr);
|
||||
|
||||
// Pipe is configured and allocated successfully
|
||||
return ul_pipe;
|
||||
}
|
||||
|
||||
uhd_enable_pipe(ul_pipe);
|
||||
|
||||
uhd_configure_pipe(ul_pipe, ul_interval, ul_addr, ul_type, ul_dir,
|
||||
ul_maxsize, ul_bank, UOTGHS_HSTPIPCFG_AUTOSW);
|
||||
|
||||
uhd_allocate_memory(ul_pipe);
|
||||
|
||||
if (!Is_uhd_pipe_configured(ul_pipe))
|
||||
{
|
||||
uhd_disable_pipe(ul_pipe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uhd_configure_address(ul_pipe, ul_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UHD_EP_Free(uint32_t add, uint32_t endp)
|
||||
/**
|
||||
* \brief Free a pipe.
|
||||
*
|
||||
* \param ul_pipe Pipe number to free.
|
||||
*/
|
||||
void UHD_Pipe_Free(uint32_t ul_pipe)
|
||||
{
|
||||
// Search endpoint(s) in all pipes
|
||||
for (uint8_t pipe = 0; pipe < UOTGHS_EPT_NUM; pipe++)
|
||||
{
|
||||
if (!Is_uhd_pipe_enabled(pipe))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (add != uhd_get_configured_address(pipe))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if (endp != 0xFF)
|
||||
{
|
||||
// Disable specific endpoint number
|
||||
if (endp != uhd_get_pipe_endpoint_address(pipe))
|
||||
{
|
||||
continue; // Mismatch
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Unalloc pipe
|
||||
uhd_disable_pipe(pipe);
|
||||
uhd_unallocate_memory(pipe);
|
||||
uhd_reset_pipe(pipe);
|
||||
}
|
||||
// Unalloc pipe
|
||||
uhd_disable_pipe(ul_pipe);
|
||||
uhd_unallocate_memory(ul_pipe);
|
||||
uhd_reset_pipe(ul_pipe);
|
||||
}
|
||||
|
||||
uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data)
|
||||
/**
|
||||
* \brief Read from a pipe.
|
||||
*
|
||||
* \param ul_pipe Pipe number.
|
||||
* \param ul_size Maximum number of data to read.
|
||||
* \param data Buffer to store the data.
|
||||
*
|
||||
* \return number of data read.
|
||||
*/
|
||||
uint32_t UHD_Pipe_Read(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data)
|
||||
{
|
||||
uint8_t *ptr_ep_data = 0;
|
||||
uint8_t nb_byte_received = 0;
|
||||
uint32_t ul_nb_trans = 0;
|
||||
|
||||
// Get information to read data
|
||||
nb_byte_received = uhd_byte_count(ul_ep);
|
||||
nb_byte_received = uhd_byte_count(ul_pipe);
|
||||
|
||||
ptr_ep_data = (uint8_t *) & uhd_get_pipe_fifo_access(ul_ep, 8);
|
||||
ptr_ep_data = (uint8_t *) & uhd_get_pipe_fifo_access(ul_pipe, 8);
|
||||
|
||||
// Copy data from pipe to payload buffer
|
||||
while (ul_size && nb_byte_received) {
|
||||
@ -356,98 +376,111 @@ uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data)
|
||||
return ul_nb_trans;
|
||||
}
|
||||
|
||||
void UHD_EP_Write(uint32_t ul_ep, uint32_t ul_size, uint8_t* data)
|
||||
/**
|
||||
* \brief Write into a pipe.
|
||||
*
|
||||
* \param ul_pipe Pipe number.
|
||||
* \param ul_size Maximum number of data to read.
|
||||
* \param data Buffer containing data to write.
|
||||
*/
|
||||
void UHD_Pipe_Write(uint32_t ul_pipe, uint32_t ul_size, uint8_t* data)
|
||||
{
|
||||
volatile uint8_t *ptr_ep_data = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
// Check pipe
|
||||
if (!Is_uhd_pipe_enabled(ul_ep))
|
||||
if (!Is_uhd_pipe_enabled(ul_pipe))
|
||||
{
|
||||
// Endpoint not valid
|
||||
TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe is not enabled!\r\n");)
|
||||
return;
|
||||
}
|
||||
|
||||
ptr_ep_data = (volatile uint8_t *)&uhd_get_pipe_fifo_access(ul_ep, 8);
|
||||
ptr_ep_data = (volatile uint8_t *)&uhd_get_pipe_fifo_access(ul_pipe, 8);
|
||||
for (i = 0; i < ul_size; ++i)
|
||||
*ptr_ep_data++ = *data++;
|
||||
}
|
||||
|
||||
void UHD_EP_Send(uint32_t ul_ep, uint32_t ul_token_type)
|
||||
/**
|
||||
* \brief Send a pipe content.
|
||||
*
|
||||
* \param ul_pipe Pipe number.
|
||||
* \param ul_token_type Token type.
|
||||
*/
|
||||
void UHD_Pipe_Send(uint32_t ul_pipe, uint32_t ul_token_type)
|
||||
{
|
||||
// Check pipe
|
||||
if (!Is_uhd_pipe_enabled(ul_ep))
|
||||
if (!Is_uhd_pipe_enabled(ul_pipe))
|
||||
{
|
||||
// Endpoint not valid
|
||||
TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe %lu is not enabled!\r\n", ul_ep);)
|
||||
TRACE_UOTGHS_HOST(printf("/!\\ UHD_EP_Send : pipe %lu is not enabled!\r\n", ul_pipe);)
|
||||
return;
|
||||
}
|
||||
|
||||
// Set token type for zero length packet
|
||||
// When actually using the FIFO, pipe token MUST be configured first
|
||||
uhd_configure_pipe_token(ul_ep, ul_token_type);
|
||||
uhd_configure_pipe_token(ul_pipe, ul_token_type);
|
||||
|
||||
// Clear interrupt flags
|
||||
uhd_ack_setup_ready(ul_ep);
|
||||
uhd_ack_in_received(ul_ep);
|
||||
uhd_ack_out_ready(ul_ep);
|
||||
uhd_ack_short_packet(ul_ep);
|
||||
uhd_ack_setup_ready(ul_pipe);
|
||||
uhd_ack_in_received(ul_pipe);
|
||||
uhd_ack_out_ready(ul_pipe);
|
||||
uhd_ack_short_packet(ul_pipe);
|
||||
uhd_ack_nak_received(ul_pipe);
|
||||
|
||||
// Send actual packet
|
||||
uhd_ack_fifocon(ul_ep);
|
||||
uhd_unfreeze_pipe(ul_ep);
|
||||
uhd_ack_fifocon(ul_pipe);
|
||||
uhd_unfreeze_pipe(ul_pipe);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check is transfer is complete.
|
||||
* \brief Check for pipe transfer completion.
|
||||
*
|
||||
* \param ul_add Address of remote device for pipe 0.
|
||||
* \param ul_ep_size Actual size of the FIFO in bytes.
|
||||
* \param ul_pipe Pipe number.
|
||||
* \param ul_token_type Token type.
|
||||
*
|
||||
* \retval 0 transfer is not complete.
|
||||
* \retval 1 transfer is complete.
|
||||
*/
|
||||
uint32_t UHD_EP_Is_Transfer_Complete(uint32_t ul_ep, uint32_t ul_token_type)
|
||||
uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type)
|
||||
{
|
||||
// Check for transfer completion depending on token type
|
||||
switch (ul_token_type)
|
||||
{
|
||||
case UOTGHS_HSTPIPCFG_PTOKEN_SETUP:
|
||||
if (Is_uhd_setup_ready(ul_ep))
|
||||
if (Is_uhd_setup_ready(ul_pipe))
|
||||
{
|
||||
uhd_freeze_pipe(ul_ep);
|
||||
uhd_ack_setup_ready(ul_ep);
|
||||
uhd_freeze_pipe(ul_pipe);
|
||||
uhd_ack_setup_ready(ul_pipe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case UOTGHS_HSTPIPCFG_PTOKEN_IN:
|
||||
if (Is_uhd_in_received(ul_ep))
|
||||
if (Is_uhd_in_received(ul_pipe))
|
||||
{
|
||||
// In case of low USB speed and with a high CPU frequency,
|
||||
// a ACK from host can be always running on USB line
|
||||
// then wait end of ACK on IN pipe.
|
||||
while(!Is_uhd_pipe_frozen(ul_ep))
|
||||
while(!Is_uhd_pipe_frozen(ul_pipe))
|
||||
;
|
||||
|
||||
// IN packet received
|
||||
uhd_ack_in_received(ul_ep);
|
||||
uhd_ack_in_received(ul_pipe);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
case UOTGHS_HSTPIPCFG_PTOKEN_OUT:
|
||||
if (Is_uhd_out_ready(ul_ep))
|
||||
if (Is_uhd_out_ready(ul_pipe))
|
||||
{
|
||||
// OUT packet sent
|
||||
uhd_freeze_pipe(ul_ep);
|
||||
uhd_ack_out_ready(ul_ep);
|
||||
uhd_freeze_pipe(ul_pipe);
|
||||
uhd_ack_out_ready(ul_pipe);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing to report
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@ -99,14 +99,14 @@ pwmc.o:
|
||||
00000000 T PWMC_SetSyncChannelUpdateUnlock
|
||||
00000000 T PWMC_WriteBuffer
|
||||
U __assert_func
|
||||
00000000 r __func__.3296
|
||||
00000000 r __func__.3307
|
||||
00000000 r __func__.3322
|
||||
00000000 r __func__.3333
|
||||
00000000 r __func__.3344
|
||||
00000000 r __func__.3351
|
||||
00000000 r __func__.3435
|
||||
00000000 r __func__.3441
|
||||
00000000 r __func__.3295
|
||||
00000000 r __func__.3306
|
||||
00000000 r __func__.3321
|
||||
00000000 r __func__.3332
|
||||
00000000 r __func__.3343
|
||||
00000000 r __func__.3350
|
||||
00000000 r __func__.3434
|
||||
00000000 r __func__.3440
|
||||
|
||||
rtc.o:
|
||||
00000000 T RTC_ClearSCCR
|
||||
@ -122,9 +122,9 @@ rtc.o:
|
||||
00000000 T RTC_SetTime
|
||||
00000000 T RTC_SetTimeAlarm
|
||||
U __assert_func
|
||||
00000000 r __func__.3293
|
||||
00000000 r __func__.3302
|
||||
00000000 r __func__.3307
|
||||
00000000 r __func__.3292
|
||||
00000000 r __func__.3301
|
||||
00000000 r __func__.3306
|
||||
|
||||
rtt.o:
|
||||
00000000 T RTT_EnableIT
|
||||
@ -133,8 +133,8 @@ rtt.o:
|
||||
00000000 T RTT_SetAlarm
|
||||
00000000 T RTT_SetPrescaler
|
||||
U __assert_func
|
||||
00000000 r __func__.3300
|
||||
00000000 r __func__.3308
|
||||
00000000 r __func__.3299
|
||||
00000000 r __func__.3307
|
||||
|
||||
spi.o:
|
||||
00000000 T SPI_Configure
|
||||
@ -155,9 +155,9 @@ tc.o:
|
||||
00000000 T TC_Start
|
||||
00000000 T TC_Stop
|
||||
U __assert_func
|
||||
00000000 r __func__.3295
|
||||
00000000 r __func__.3301
|
||||
00000000 r __func__.3307
|
||||
00000000 r __func__.3294
|
||||
00000000 r __func__.3300
|
||||
00000000 r __func__.3306
|
||||
|
||||
timetick.o:
|
||||
00000000 T GetTickCount
|
||||
@ -184,18 +184,18 @@ twi.o:
|
||||
00000000 T TWI_TransferComplete
|
||||
00000000 T TWI_WriteByte
|
||||
U __assert_func
|
||||
00000000 r __func__.3660
|
||||
00000000 r __func__.3675
|
||||
00000000 r __func__.3679
|
||||
00000000 r __func__.3686
|
||||
00000000 r __func__.3690
|
||||
00000000 r __func__.3695
|
||||
00000000 r __func__.3703
|
||||
00000000 r __func__.3717
|
||||
00000000 r __func__.3722
|
||||
00000000 r __func__.3726
|
||||
00000000 r __func__.3731
|
||||
00000000 r __func__.3735
|
||||
00000000 r __func__.3659
|
||||
00000000 r __func__.3674
|
||||
00000000 r __func__.3678
|
||||
00000000 r __func__.3685
|
||||
00000000 r __func__.3689
|
||||
00000000 r __func__.3694
|
||||
00000000 r __func__.3702
|
||||
00000000 r __func__.3716
|
||||
00000000 r __func__.3721
|
||||
00000000 r __func__.3725
|
||||
00000000 r __func__.3730
|
||||
00000000 r __func__.3734
|
||||
|
||||
usart.o:
|
||||
00000000 T USART_Configure
|
||||
@ -214,7 +214,7 @@ usart.o:
|
||||
00000000 T USART_Write
|
||||
00000000 T USART_WriteBuffer
|
||||
U __assert_func
|
||||
00000000 r __func__.3581
|
||||
00000000 r __func__.3580
|
||||
|
||||
wdt.o:
|
||||
00000000 T WDT_Disable
|
||||
@ -385,20 +385,19 @@ uotghs_device.o:
|
||||
|
||||
uotghs_host.o:
|
||||
00000000 T UHD_BusReset
|
||||
00000000 T UHD_EP0_Alloc
|
||||
00000000 T UHD_EP_Alloc
|
||||
00000000 T UHD_EP_Free
|
||||
00000000 T UHD_EP_Is_Transfer_Complete
|
||||
00000000 T UHD_EP_Read
|
||||
00000000 T UHD_EP_Send
|
||||
00000000 T UHD_EP_Write
|
||||
00000000 T UHD_GetVBUSState
|
||||
00000000 t UHD_ISR
|
||||
00000000 T UHD_Init
|
||||
00000000 T UHD_Pipe0_Alloc
|
||||
00000000 T UHD_Pipe_Alloc
|
||||
00000000 T UHD_Pipe_Free
|
||||
00000000 T UHD_Pipe_Is_Transfer_Complete
|
||||
00000000 T UHD_Pipe_Read
|
||||
00000000 T UHD_Pipe_Send
|
||||
00000000 T UHD_Pipe_Write
|
||||
00000000 T UHD_SetStack
|
||||
U g_interrupt_enabled
|
||||
U gpf_isr
|
||||
U iprintf
|
||||
U pmc_enable_periph_clk
|
||||
U pmc_enable_udpck
|
||||
U pmc_enable_upll_clock
|
||||
|
Loading…
x
Reference in New Issue
Block a user