Repository for import to local machine
Dependencies: DMBasicGUI DMSupport
Diff: USBHostGC.cpp
- Revision:
- 0:47c880c1463d
- Child:
- 1:a5258871b33d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHostGC.cpp Wed Jan 13 13:17:05 2016 +0000 @@ -0,0 +1,217 @@ +/** + * A class to communicate with a USB GC. + * + * *** Important note - when reading data from the USB device, you must do this into memory allocated using *** + * *** the 'getSafeMem' function of the USBHost class. If you read it into 'normal' memory, your code will crash. *** + * *** This is my experience so far, at least. This applies, e.g. to all the 'Get...' functions below. *** + * *** (There may, of course, be a simple explanation for this, but if so, I am not currently aware of it.) *** + * *** This is why (currently) all the 'Get...' functions allocate a buffer from safe memory, *** + * *** read the data into it, then copy the data into the buffer provided by the caller. *** + */ + +#include "USBHostGC.h" + +extern void EasyGUIDebugPrint(char *stuffToPrint, short X, short Y); + + +USBHostGC::USBHostGC() +{ + debugWindow = NULL; + + usbHost = USBHost::getHostInst(); + + reportBuffer = NULL; + + NoDeviceConnected(); // So far... + + alreadyInSetDeviceReport = false; +} + +USBHostGC::~USBHostGC() +{ + NoDeviceConnected(); +} + +void USBHostGC::NoDeviceConnected(void) +{ + deviceIsGC = false; + intfGC = -1; + intInEndpointGC = NULL; + usbGCDeviceConnected = NULL; + + if (reportBuffer != NULL) { + usbHost->returnSafeMem(reportBuffer); + reportBuffer = NULL; + } +} + +void USBHostGC::DebugPrint(const char* debugText) +{ + if(debugWindow != NULL) { + swim_put_text(debugWindow, debugText); + } +} + +void USBHostGC::AllocateReportBuffer(void) +{ + int reportSize = GC_MESSAGE_LENGTH; + + if (intInEndpointGC != NULL) { + int intInEndpointSize = intInEndpointGC->getSize(); + if (intInEndpointSize > reportSize) { + reportSize = intInEndpointSize; + } + } + + reportBuffer = usbHost->getSafeMem(reportSize); +} + +bool USBHostGC::AttachGCDevice(USBDeviceConnected* usbDeviceConnected) +{ + intInEndpointGC = usbDeviceConnected->getEndpoint(intfGC, INTERRUPT_ENDPOINT, IN); + if (!intInEndpointGC) { + DebugPrint("AttachGCDevice - interrupt endpoint in not found - returning false\n"); + NoDeviceConnected(); + return false; + } + + usbDeviceConnected->setName("GC", intfGC); + + usbHost->registerDriver(usbDeviceConnected, intfGC, this, &USBHostGC::NoDeviceConnected); + + intInEndpointGC->attach(this, &USBHostGC::RXHandler); + + if (reportBuffer == NULL) { + AllocateReportBuffer(); + } + + usbHost->interruptRead(usbDeviceConnected, intInEndpointGC, reportBuffer, intInEndpointGC->getSize(), false); + + usbGCDeviceConnected = usbDeviceConnected; + + return true; +} + +void USBHostGC::RXHandler(void) +{ + responseReceived = true; + + if (usbGCDeviceConnected) { + usbHost->interruptRead(usbGCDeviceConnected, intInEndpointGC, reportBuffer, intInEndpointGC->getSize(), false); + } +} + +bool USBHostGC::ExecutingSetDeviceReport(void) +{ + return alreadyInSetDeviceReport; +} + +USB_TYPE USBHostGC::SetDeviceReport(USBDeviceConnected * dev, const char* report, char* response) +{ + // Neither this function, nor the GC itself, are re-entrant... + if(alreadyInSetDeviceReport) { + return USB_TYPE_PROCESSING; + } + + alreadyInSetDeviceReport = true; + + if (reportBuffer == NULL) { + AllocateReportBuffer(); + } + + int i; + for (i = 0; (i < GC_MESSAGE_LENGTH) && (report[i]); ++i) { + reportBuffer[i] = (uint8_t) report[i]; + } + //reportBuffer[i++] = (uint8_t) GC_CR; // Append <CR> - make *sure* it is the same code the GC expects + // Fill remainder of buffer with nulls, to pad out to 10 bytes + for ( ; i < GC_MESSAGE_LENGTH; ++i) { + reportBuffer[i] = 0; + } + //reportBuffer[GC_MESSAGE_LENGTH - 1] = (uint8_t) GC_CR; + + responseReceived = false; // Synchronise with RXHandler + + //EasyGUIDebugPrint("SetDeviceReport - before controlWrite", 20,80); + USB_TYPE t = usbHost->controlWrite( dev, + 1, // Non-zero - tells GC - set report, not set configuration + SET_CONFIGURATION, + 0, + 0, reportBuffer, GC_MESSAGE_LENGTH); + //EasyGUIDebugPrint("SetDeviceReport - after controlWrite", 20,100); + + while (!responseReceived) { + // wait... + } + + //EasyGUIDebugPrint("SetDeviceReport - after wait for response", 20,120); + + // RXHandler has now received the response - return it to the caller + + for (i = 0; i < GC_MESSAGE_LENGTH; ++i) { + response[i] = reportBuffer[i]; + } + response[i] = '\0'; + + alreadyInSetDeviceReport = false; + + return t; +} + +// Part of IUSBEnumerator interface +/* virtual */ void USBHostGC::setVidPid(uint16_t vid, uint16_t pid) +{ + char buff[100]; + sprintf(buff, "setVidPid(%d %X, %d %X)\n", vid, vid, pid, pid); + DebugPrint(buff); + + deviceIsGC = ((vid == GC_VENDOR_ID) && (pid == GC_PRODUCT_ID)); + + DebugPrint(deviceIsGC ? "Device is a GC\n" : "Device is *not* a GC\n"); +} + +// Part of IUSBEnumerator interface - must return true if the interface should be parsed +/* virtual */ bool USBHostGC::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) +{ + char buff[100]; + sprintf(buff, "parseInterface(%d %X, %d %X, %d %X, %d %X)\n", intf_nb, intf_nb, intf_class, intf_class, intf_subclass, intf_subclass, intf_protocol, intf_protocol); + DebugPrint(buff); + + // setVidPid should have been called before this - + // assume it will have identified whether or not the device is a GC + if (deviceIsGC) { + if ((intfGC == -1) && + (intf_class == HID_CLASS)) { + // Don't care about subclass and protocol in this case + + intfGC = intf_nb; + DebugPrint(" **** GC found **** \n"); + } + DebugPrint("GC found - parseInterface returning true\n"); + return true; + } + + DebugPrint("No GC found - parseInterface returning false\n"); + return false; +} + +// Part of IUSBEnumerator interface - must return true if the endpoint will be used +/* virtual */ bool USBHostGC::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) +{ + char buff[100]; + sprintf(buff, "useEndPoint(%d %X, %d %X, %d %X)\n", intf_nb, intf_nb, type, type, dir, dir); + DebugPrint(buff); + + if (deviceIsGC) { + if ((intfGC == intf_nb) && + (type == INTERRUPT_ENDPOINT) && + (dir == IN)) { + DebugPrint("GC endpoint found - useEndPoint returning true\n"); + return true; + } + } + + // 'else' + DebugPrint("GC endpoint not found - useEndpoint returning false\n"); + return false; +}