Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: DMBasicGUI DMSupport
USBHostGC.cpp
00001 /** 00002 * A class to communicate with a USB GC. 00003 * 00004 * *** Important note - when reading data from the USB device, you must do this into memory allocated using *** 00005 * *** the 'getSafeMem' function of the USBHost class. If you read it into 'normal' memory, your code will crash. *** 00006 * *** This is my experience so far, at least. This applies, e.g. to all the 'Get...' functions below. *** 00007 * *** (There may, of course, be a simple explanation for this, but if so, I am not currently aware of it.) *** 00008 * *** This is why (currently) all the 'Get...' functions allocate a buffer from safe memory, *** 00009 * *** read the data into it, then copy the data into the buffer provided by the caller. *** 00010 */ 00011 00012 #include "USBHostGC.h" 00013 00014 extern void EasyGUIDebugPrint(char *stuffToPrint, short X, short Y); 00015 00016 /* 00017 Displays the specified text string at the specified location in the currently-displayed easyGUI page. 00018 00019 Defined in main.cpp - and omits the 'ALLOW_DEBUG_PRINTS' #define 00020 */ 00021 extern void SpecialDebugPrint(char *stuffToPrint, short X, short Y); 00022 00023 USBHostGC::USBHostGC() 00024 { 00025 debugWindow = NULL; 00026 00027 usbHost = USBHost::getHostInst(); 00028 00029 reportBuffer = NULL; 00030 00031 NoDeviceConnected(); // So far... 00032 00033 alreadyInSetDeviceReport = false; 00034 } 00035 00036 USBHostGC::~USBHostGC() 00037 { 00038 NoDeviceConnected(); 00039 } 00040 00041 void USBHostGC::NoDeviceConnected(void) 00042 { 00043 deviceIsGC = false; 00044 intfGC = -1; 00045 intInEndpointGC = NULL; 00046 usbGCDeviceConnected = NULL; 00047 00048 if (reportBuffer != NULL) { 00049 usbHost->returnSafeMem(reportBuffer); 00050 reportBuffer = NULL; 00051 } 00052 } 00053 00054 void USBHostGC::DebugPrint(const char* debugText) 00055 { 00056 if(debugWindow != NULL) { 00057 swim_put_text(debugWindow, debugText); 00058 } 00059 } 00060 00061 /* 00062 Data sent to/from the GC over the USB link has to be in 'safe' memory - 00063 it will crash if ordinary memory is used. This function allocates 00064 a buffer in safe memory 00065 */ 00066 void USBHostGC::AllocateReportBuffer(void) 00067 { 00068 int reportSize = GC_MESSAGE_LENGTH; 00069 00070 if (intInEndpointGC != NULL) { 00071 int intInEndpointSize = intInEndpointGC->getSize(); 00072 if (intInEndpointSize > reportSize) { 00073 reportSize = intInEndpointSize; 00074 } 00075 } 00076 00077 reportBuffer = usbHost->getSafeMem(reportSize); 00078 } 00079 00080 /* 00081 Attach the specified USB device to this instance 00082 */ 00083 bool USBHostGC::AttachGCDevice(USBDeviceConnected* usbDeviceConnected) 00084 { 00085 intInEndpointGC = usbDeviceConnected->getEndpoint(intfGC, INTERRUPT_ENDPOINT, IN); 00086 if (!intInEndpointGC) { 00087 DebugPrint("AttachGCDevice - interrupt endpoint in not found - returning false\n"); 00088 NoDeviceConnected(); 00089 return false; 00090 } 00091 00092 usbDeviceConnected->setName("GC", intfGC); 00093 00094 usbHost->registerDriver(usbDeviceConnected, intfGC, this, &USBHostGC::NoDeviceConnected); 00095 00096 intInEndpointGC->attach(this, &USBHostGC::RXHandler); 00097 00098 if (reportBuffer == NULL) { 00099 AllocateReportBuffer(); 00100 } 00101 00102 usbHost->interruptRead(usbDeviceConnected, intInEndpointGC, reportBuffer, intInEndpointGC->getSize(), false); 00103 00104 usbGCDeviceConnected = usbDeviceConnected; 00105 00106 return true; 00107 } 00108 00109 /* 00110 Invoked by the OS when a USB read (from the GC) has completed 00111 */ 00112 void USBHostGC::RXHandler(void) 00113 { 00114 responseReceived = true; 00115 00116 if (usbGCDeviceConnected) { 00117 usbHost->interruptRead(usbGCDeviceConnected, intInEndpointGC, reportBuffer, intInEndpointGC->getSize(), false); 00118 } 00119 } 00120 00121 /* 00122 The SetDeviceReport function is not re-entrant (and even if it were, the GC is not, so simultaneous calls 00123 to SetDeviceReport would not work anyway). 00124 00125 This function tells the caller whether or not a 'SetDeviceReport' call is in progress. 00126 It returns true if so, false if not. 00127 00128 The expectation is that the caller will wait until this function returns false 00129 before calling SetDeviceReport. 00130 */ 00131 bool USBHostGC::ExecutingSetDeviceReport(void) 00132 { 00133 return alreadyInSetDeviceReport; 00134 } 00135 00136 /* 00137 Sends a command to the GC, gets a response back. In this context, what we would think of 00138 as a 'command' is called a 'report' in the GC code - hence the use of the word 'report' here. 00139 00140 Args: a pointer to the USB device corresponding to the GC 00141 a pointer to the command/report to be sent to the GC 00142 a pointer to the buffer to contain the GC's response 00143 00144 Returns the USB_TYPE code giving the status of the transaction. 00145 */ 00146 USB_TYPE USBHostGC::SetDeviceReport(USBDeviceConnected * dev, const char* report, char* response) 00147 { 00148 // Neither this function, nor the GC itself, are re-entrant... 00149 00150 if(alreadyInSetDeviceReport) { 00151 return USB_TYPE_PROCESSING; 00152 } 00153 00154 alreadyInSetDeviceReport = true; 00155 00156 if (reportBuffer == NULL) { 00157 AllocateReportBuffer(); 00158 } 00159 00160 int i; 00161 for (i = 0; (i < GC_MESSAGE_LENGTH) && (report[i]); ++i) { 00162 reportBuffer[i] = (uint8_t) report[i]; 00163 } 00164 //reportBuffer[i++] = (uint8_t) GC_CR; // Append <CR> - make *sure* it is the same code the GC expects 00165 // Fill remainder of buffer with nulls, to pad out to 10 bytes 00166 for ( ; i < GC_MESSAGE_LENGTH; ++i) { 00167 reportBuffer[i] = 0; 00168 } 00169 //reportBuffer[GC_MESSAGE_LENGTH - 1] = (uint8_t) GC_CR; 00170 00171 responseReceived = false; // Synchronise with RXHandler 00172 00173 //#define ALLOW_DEBUG_PRINTS_HERE 00174 #ifdef ALLOW_DEBUG_PRINTS_HERE 00175 SpecialDebugPrint("SetDeviceReport - before controlWrite", 20,80); 00176 #endif 00177 USB_TYPE t = usbHost->controlWrite( dev, 00178 1, // Non-zero - tells GC - set report, not set configuration 00179 SET_CONFIGURATION, 00180 0, 00181 0, reportBuffer, GC_MESSAGE_LENGTH); 00182 //EasyGUIDebugPrint("SetDeviceReport - after controlWrite", 20,100); 00183 00184 #ifdef ALLOW_DEBUG_PRINTS_HERE 00185 SpecialDebugPrint("SetDeviceReport - waiting for response", 20,120); 00186 #endif 00187 00188 while (!responseReceived) { 00189 // wait... 00190 Thread::wait(10); // *** With this, we can successfully call this function from the Ethernet thread *** 00191 // (without it, this function enters an infinite loop at this point when called 00192 // from the Ethernet thread, although it is OK from the main thread) 00193 } 00194 00195 #ifdef ALLOW_DEBUG_PRINTS_HERE 00196 SpecialDebugPrint("SetDeviceReport - after wait for response", 20,120); 00197 #endif 00198 00199 // RXHandler has now received the response - return it to the caller 00200 00201 for (i = 0; i < GC_MESSAGE_LENGTH; ++i) { 00202 response[i] = reportBuffer[i]; 00203 } 00204 response[i] = '\0'; 00205 00206 alreadyInSetDeviceReport = false; 00207 00208 return t; 00209 } 00210 00211 // Part of IUSBEnumerator interface 00212 /* virtual */ void USBHostGC::setVidPid(uint16_t vid, uint16_t pid) 00213 { 00214 char buff[100]; 00215 sprintf(buff, "setVidPid(%d %X, %d %X)\n", vid, vid, pid, pid); 00216 DebugPrint(buff); 00217 00218 deviceIsGC = ((vid == GC_VENDOR_ID) && ((pid == GC_PRODUCT_ID) || (pid == GC_PRODUCT_ID_2))); 00219 00220 DebugPrint(deviceIsGC ? "Device is a GC\n" : "Device is *not* a GC\n"); 00221 } 00222 00223 // Part of IUSBEnumerator interface - must return true if the interface should be parsed 00224 /* virtual */ bool USBHostGC::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) 00225 { 00226 char buff[100]; 00227 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); 00228 DebugPrint(buff); 00229 00230 // setVidPid should have been called before this - 00231 // assume it will have identified whether or not the device is a GC 00232 if (deviceIsGC) { 00233 if ((intfGC == -1) && 00234 (intf_class == HID_CLASS)) { 00235 // Don't care about subclass and protocol in this case 00236 00237 intfGC = intf_nb; 00238 DebugPrint(" **** GC found **** \n"); 00239 } 00240 DebugPrint("GC found - parseInterface returning true\n"); 00241 return true; 00242 } 00243 00244 DebugPrint("No GC found - parseInterface returning false\n"); 00245 return false; 00246 } 00247 00248 // Part of IUSBEnumerator interface - must return true if the endpoint will be used 00249 /* virtual */ bool USBHostGC::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) 00250 { 00251 char buff[100]; 00252 sprintf(buff, "useEndPoint(%d %X, %d %X, %d %X)\n", intf_nb, intf_nb, type, type, dir, dir); 00253 DebugPrint(buff); 00254 00255 if (deviceIsGC) { 00256 if ((intfGC == intf_nb) && 00257 (type == INTERRUPT_ENDPOINT) && 00258 (dir == IN)) { 00259 DebugPrint("GC endpoint found - useEndPoint returning true\n"); 00260 return true; 00261 } 00262 } 00263 00264 // 'else' 00265 DebugPrint("GC endpoint not found - useEndpoint returning false\n"); 00266 return false; 00267 }
Generated on Tue Jul 19 2022 00:31:07 by
1.7.2