Repository for import to local machine
Dependencies: DMBasicGUI DMSupport
USBHostGC.cpp
- Committer:
- jmitc91516
- Date:
- 2016-01-13
- Revision:
- 0:47c880c1463d
- Child:
- 1:a5258871b33d
File content as of revision 0:47c880c1463d:
/** * 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; }