Repository for import to local machine

Dependencies:   DMBasicGUI DMSupport

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;
+}