Repository for import to local machine
Dependencies: DMBasicGUI DMSupport
USBHostGC.cpp@1:a5258871b33d, 2017-07-20 (annotated)
- Committer:
- jmitc91516
- Date:
- Thu Jul 20 08:42:29 2017 +0000
- Revision:
- 1:a5258871b33d
- Parent:
- 0:47c880c1463d
Version before re-layout (July 2017). Also for mbed CLI import to local machine.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jmitc91516 | 0:47c880c1463d | 1 | /** |
jmitc91516 | 0:47c880c1463d | 2 | * A class to communicate with a USB GC. |
jmitc91516 | 0:47c880c1463d | 3 | * |
jmitc91516 | 0:47c880c1463d | 4 | * *** Important note - when reading data from the USB device, you must do this into memory allocated using *** |
jmitc91516 | 0:47c880c1463d | 5 | * *** the 'getSafeMem' function of the USBHost class. If you read it into 'normal' memory, your code will crash. *** |
jmitc91516 | 0:47c880c1463d | 6 | * *** This is my experience so far, at least. This applies, e.g. to all the 'Get...' functions below. *** |
jmitc91516 | 0:47c880c1463d | 7 | * *** (There may, of course, be a simple explanation for this, but if so, I am not currently aware of it.) *** |
jmitc91516 | 0:47c880c1463d | 8 | * *** This is why (currently) all the 'Get...' functions allocate a buffer from safe memory, *** |
jmitc91516 | 0:47c880c1463d | 9 | * *** read the data into it, then copy the data into the buffer provided by the caller. *** |
jmitc91516 | 0:47c880c1463d | 10 | */ |
jmitc91516 | 0:47c880c1463d | 11 | |
jmitc91516 | 0:47c880c1463d | 12 | #include "USBHostGC.h" |
jmitc91516 | 0:47c880c1463d | 13 | |
jmitc91516 | 0:47c880c1463d | 14 | extern void EasyGUIDebugPrint(char *stuffToPrint, short X, short Y); |
jmitc91516 | 0:47c880c1463d | 15 | |
jmitc91516 | 1:a5258871b33d | 16 | /* |
jmitc91516 | 1:a5258871b33d | 17 | Displays the specified text string at the specified location in the currently-displayed easyGUI page. |
jmitc91516 | 1:a5258871b33d | 18 | |
jmitc91516 | 1:a5258871b33d | 19 | Defined in main.cpp - and omits the 'ALLOW_DEBUG_PRINTS' #define |
jmitc91516 | 1:a5258871b33d | 20 | */ |
jmitc91516 | 1:a5258871b33d | 21 | extern void SpecialDebugPrint(char *stuffToPrint, short X, short Y); |
jmitc91516 | 0:47c880c1463d | 22 | |
jmitc91516 | 0:47c880c1463d | 23 | USBHostGC::USBHostGC() |
jmitc91516 | 0:47c880c1463d | 24 | { |
jmitc91516 | 0:47c880c1463d | 25 | debugWindow = NULL; |
jmitc91516 | 0:47c880c1463d | 26 | |
jmitc91516 | 0:47c880c1463d | 27 | usbHost = USBHost::getHostInst(); |
jmitc91516 | 0:47c880c1463d | 28 | |
jmitc91516 | 0:47c880c1463d | 29 | reportBuffer = NULL; |
jmitc91516 | 0:47c880c1463d | 30 | |
jmitc91516 | 0:47c880c1463d | 31 | NoDeviceConnected(); // So far... |
jmitc91516 | 0:47c880c1463d | 32 | |
jmitc91516 | 0:47c880c1463d | 33 | alreadyInSetDeviceReport = false; |
jmitc91516 | 0:47c880c1463d | 34 | } |
jmitc91516 | 0:47c880c1463d | 35 | |
jmitc91516 | 0:47c880c1463d | 36 | USBHostGC::~USBHostGC() |
jmitc91516 | 0:47c880c1463d | 37 | { |
jmitc91516 | 0:47c880c1463d | 38 | NoDeviceConnected(); |
jmitc91516 | 0:47c880c1463d | 39 | } |
jmitc91516 | 0:47c880c1463d | 40 | |
jmitc91516 | 0:47c880c1463d | 41 | void USBHostGC::NoDeviceConnected(void) |
jmitc91516 | 0:47c880c1463d | 42 | { |
jmitc91516 | 0:47c880c1463d | 43 | deviceIsGC = false; |
jmitc91516 | 0:47c880c1463d | 44 | intfGC = -1; |
jmitc91516 | 0:47c880c1463d | 45 | intInEndpointGC = NULL; |
jmitc91516 | 0:47c880c1463d | 46 | usbGCDeviceConnected = NULL; |
jmitc91516 | 0:47c880c1463d | 47 | |
jmitc91516 | 0:47c880c1463d | 48 | if (reportBuffer != NULL) { |
jmitc91516 | 0:47c880c1463d | 49 | usbHost->returnSafeMem(reportBuffer); |
jmitc91516 | 0:47c880c1463d | 50 | reportBuffer = NULL; |
jmitc91516 | 0:47c880c1463d | 51 | } |
jmitc91516 | 0:47c880c1463d | 52 | } |
jmitc91516 | 0:47c880c1463d | 53 | |
jmitc91516 | 0:47c880c1463d | 54 | void USBHostGC::DebugPrint(const char* debugText) |
jmitc91516 | 0:47c880c1463d | 55 | { |
jmitc91516 | 0:47c880c1463d | 56 | if(debugWindow != NULL) { |
jmitc91516 | 0:47c880c1463d | 57 | swim_put_text(debugWindow, debugText); |
jmitc91516 | 0:47c880c1463d | 58 | } |
jmitc91516 | 0:47c880c1463d | 59 | } |
jmitc91516 | 0:47c880c1463d | 60 | |
jmitc91516 | 1:a5258871b33d | 61 | /* |
jmitc91516 | 1:a5258871b33d | 62 | Data sent to/from the GC over the USB link has to be in 'safe' memory - |
jmitc91516 | 1:a5258871b33d | 63 | it will crash if ordinary memory is used. This function allocates |
jmitc91516 | 1:a5258871b33d | 64 | a buffer in safe memory |
jmitc91516 | 1:a5258871b33d | 65 | */ |
jmitc91516 | 0:47c880c1463d | 66 | void USBHostGC::AllocateReportBuffer(void) |
jmitc91516 | 0:47c880c1463d | 67 | { |
jmitc91516 | 0:47c880c1463d | 68 | int reportSize = GC_MESSAGE_LENGTH; |
jmitc91516 | 0:47c880c1463d | 69 | |
jmitc91516 | 0:47c880c1463d | 70 | if (intInEndpointGC != NULL) { |
jmitc91516 | 0:47c880c1463d | 71 | int intInEndpointSize = intInEndpointGC->getSize(); |
jmitc91516 | 0:47c880c1463d | 72 | if (intInEndpointSize > reportSize) { |
jmitc91516 | 0:47c880c1463d | 73 | reportSize = intInEndpointSize; |
jmitc91516 | 0:47c880c1463d | 74 | } |
jmitc91516 | 0:47c880c1463d | 75 | } |
jmitc91516 | 0:47c880c1463d | 76 | |
jmitc91516 | 0:47c880c1463d | 77 | reportBuffer = usbHost->getSafeMem(reportSize); |
jmitc91516 | 0:47c880c1463d | 78 | } |
jmitc91516 | 0:47c880c1463d | 79 | |
jmitc91516 | 1:a5258871b33d | 80 | /* |
jmitc91516 | 1:a5258871b33d | 81 | Attach the specified USB device to this instance |
jmitc91516 | 1:a5258871b33d | 82 | */ |
jmitc91516 | 0:47c880c1463d | 83 | bool USBHostGC::AttachGCDevice(USBDeviceConnected* usbDeviceConnected) |
jmitc91516 | 0:47c880c1463d | 84 | { |
jmitc91516 | 0:47c880c1463d | 85 | intInEndpointGC = usbDeviceConnected->getEndpoint(intfGC, INTERRUPT_ENDPOINT, IN); |
jmitc91516 | 0:47c880c1463d | 86 | if (!intInEndpointGC) { |
jmitc91516 | 0:47c880c1463d | 87 | DebugPrint("AttachGCDevice - interrupt endpoint in not found - returning false\n"); |
jmitc91516 | 0:47c880c1463d | 88 | NoDeviceConnected(); |
jmitc91516 | 0:47c880c1463d | 89 | return false; |
jmitc91516 | 0:47c880c1463d | 90 | } |
jmitc91516 | 0:47c880c1463d | 91 | |
jmitc91516 | 0:47c880c1463d | 92 | usbDeviceConnected->setName("GC", intfGC); |
jmitc91516 | 0:47c880c1463d | 93 | |
jmitc91516 | 0:47c880c1463d | 94 | usbHost->registerDriver(usbDeviceConnected, intfGC, this, &USBHostGC::NoDeviceConnected); |
jmitc91516 | 0:47c880c1463d | 95 | |
jmitc91516 | 0:47c880c1463d | 96 | intInEndpointGC->attach(this, &USBHostGC::RXHandler); |
jmitc91516 | 0:47c880c1463d | 97 | |
jmitc91516 | 0:47c880c1463d | 98 | if (reportBuffer == NULL) { |
jmitc91516 | 0:47c880c1463d | 99 | AllocateReportBuffer(); |
jmitc91516 | 0:47c880c1463d | 100 | } |
jmitc91516 | 0:47c880c1463d | 101 | |
jmitc91516 | 0:47c880c1463d | 102 | usbHost->interruptRead(usbDeviceConnected, intInEndpointGC, reportBuffer, intInEndpointGC->getSize(), false); |
jmitc91516 | 0:47c880c1463d | 103 | |
jmitc91516 | 0:47c880c1463d | 104 | usbGCDeviceConnected = usbDeviceConnected; |
jmitc91516 | 0:47c880c1463d | 105 | |
jmitc91516 | 0:47c880c1463d | 106 | return true; |
jmitc91516 | 0:47c880c1463d | 107 | } |
jmitc91516 | 0:47c880c1463d | 108 | |
jmitc91516 | 1:a5258871b33d | 109 | /* |
jmitc91516 | 1:a5258871b33d | 110 | Invoked by the OS when a USB read (from the GC) has completed |
jmitc91516 | 1:a5258871b33d | 111 | */ |
jmitc91516 | 0:47c880c1463d | 112 | void USBHostGC::RXHandler(void) |
jmitc91516 | 0:47c880c1463d | 113 | { |
jmitc91516 | 0:47c880c1463d | 114 | responseReceived = true; |
jmitc91516 | 0:47c880c1463d | 115 | |
jmitc91516 | 0:47c880c1463d | 116 | if (usbGCDeviceConnected) { |
jmitc91516 | 0:47c880c1463d | 117 | usbHost->interruptRead(usbGCDeviceConnected, intInEndpointGC, reportBuffer, intInEndpointGC->getSize(), false); |
jmitc91516 | 0:47c880c1463d | 118 | } |
jmitc91516 | 0:47c880c1463d | 119 | } |
jmitc91516 | 0:47c880c1463d | 120 | |
jmitc91516 | 1:a5258871b33d | 121 | /* |
jmitc91516 | 1:a5258871b33d | 122 | The SetDeviceReport function is not re-entrant (and even if it were, the GC is not, so simultaneous calls |
jmitc91516 | 1:a5258871b33d | 123 | to SetDeviceReport would not work anyway). |
jmitc91516 | 1:a5258871b33d | 124 | |
jmitc91516 | 1:a5258871b33d | 125 | This function tells the caller whether or not a 'SetDeviceReport' call is in progress. |
jmitc91516 | 1:a5258871b33d | 126 | It returns true if so, false if not. |
jmitc91516 | 1:a5258871b33d | 127 | |
jmitc91516 | 1:a5258871b33d | 128 | The expectation is that the caller will wait until this function returns false |
jmitc91516 | 1:a5258871b33d | 129 | before calling SetDeviceReport. |
jmitc91516 | 1:a5258871b33d | 130 | */ |
jmitc91516 | 0:47c880c1463d | 131 | bool USBHostGC::ExecutingSetDeviceReport(void) |
jmitc91516 | 0:47c880c1463d | 132 | { |
jmitc91516 | 0:47c880c1463d | 133 | return alreadyInSetDeviceReport; |
jmitc91516 | 0:47c880c1463d | 134 | } |
jmitc91516 | 0:47c880c1463d | 135 | |
jmitc91516 | 1:a5258871b33d | 136 | /* |
jmitc91516 | 1:a5258871b33d | 137 | Sends a command to the GC, gets a response back. In this context, what we would think of |
jmitc91516 | 1:a5258871b33d | 138 | as a 'command' is called a 'report' in the GC code - hence the use of the word 'report' here. |
jmitc91516 | 1:a5258871b33d | 139 | |
jmitc91516 | 1:a5258871b33d | 140 | Args: a pointer to the USB device corresponding to the GC |
jmitc91516 | 1:a5258871b33d | 141 | a pointer to the command/report to be sent to the GC |
jmitc91516 | 1:a5258871b33d | 142 | a pointer to the buffer to contain the GC's response |
jmitc91516 | 1:a5258871b33d | 143 | |
jmitc91516 | 1:a5258871b33d | 144 | Returns the USB_TYPE code giving the status of the transaction. |
jmitc91516 | 1:a5258871b33d | 145 | */ |
jmitc91516 | 0:47c880c1463d | 146 | USB_TYPE USBHostGC::SetDeviceReport(USBDeviceConnected * dev, const char* report, char* response) |
jmitc91516 | 0:47c880c1463d | 147 | { |
jmitc91516 | 0:47c880c1463d | 148 | // Neither this function, nor the GC itself, are re-entrant... |
jmitc91516 | 1:a5258871b33d | 149 | |
jmitc91516 | 0:47c880c1463d | 150 | if(alreadyInSetDeviceReport) { |
jmitc91516 | 0:47c880c1463d | 151 | return USB_TYPE_PROCESSING; |
jmitc91516 | 0:47c880c1463d | 152 | } |
jmitc91516 | 0:47c880c1463d | 153 | |
jmitc91516 | 0:47c880c1463d | 154 | alreadyInSetDeviceReport = true; |
jmitc91516 | 0:47c880c1463d | 155 | |
jmitc91516 | 0:47c880c1463d | 156 | if (reportBuffer == NULL) { |
jmitc91516 | 0:47c880c1463d | 157 | AllocateReportBuffer(); |
jmitc91516 | 0:47c880c1463d | 158 | } |
jmitc91516 | 0:47c880c1463d | 159 | |
jmitc91516 | 0:47c880c1463d | 160 | int i; |
jmitc91516 | 0:47c880c1463d | 161 | for (i = 0; (i < GC_MESSAGE_LENGTH) && (report[i]); ++i) { |
jmitc91516 | 0:47c880c1463d | 162 | reportBuffer[i] = (uint8_t) report[i]; |
jmitc91516 | 0:47c880c1463d | 163 | } |
jmitc91516 | 0:47c880c1463d | 164 | //reportBuffer[i++] = (uint8_t) GC_CR; // Append <CR> - make *sure* it is the same code the GC expects |
jmitc91516 | 0:47c880c1463d | 165 | // Fill remainder of buffer with nulls, to pad out to 10 bytes |
jmitc91516 | 0:47c880c1463d | 166 | for ( ; i < GC_MESSAGE_LENGTH; ++i) { |
jmitc91516 | 0:47c880c1463d | 167 | reportBuffer[i] = 0; |
jmitc91516 | 0:47c880c1463d | 168 | } |
jmitc91516 | 0:47c880c1463d | 169 | //reportBuffer[GC_MESSAGE_LENGTH - 1] = (uint8_t) GC_CR; |
jmitc91516 | 0:47c880c1463d | 170 | |
jmitc91516 | 0:47c880c1463d | 171 | responseReceived = false; // Synchronise with RXHandler |
jmitc91516 | 0:47c880c1463d | 172 | |
jmitc91516 | 1:a5258871b33d | 173 | //#define ALLOW_DEBUG_PRINTS_HERE |
jmitc91516 | 1:a5258871b33d | 174 | #ifdef ALLOW_DEBUG_PRINTS_HERE |
jmitc91516 | 1:a5258871b33d | 175 | SpecialDebugPrint("SetDeviceReport - before controlWrite", 20,80); |
jmitc91516 | 1:a5258871b33d | 176 | #endif |
jmitc91516 | 0:47c880c1463d | 177 | USB_TYPE t = usbHost->controlWrite( dev, |
jmitc91516 | 0:47c880c1463d | 178 | 1, // Non-zero - tells GC - set report, not set configuration |
jmitc91516 | 0:47c880c1463d | 179 | SET_CONFIGURATION, |
jmitc91516 | 0:47c880c1463d | 180 | 0, |
jmitc91516 | 0:47c880c1463d | 181 | 0, reportBuffer, GC_MESSAGE_LENGTH); |
jmitc91516 | 0:47c880c1463d | 182 | //EasyGUIDebugPrint("SetDeviceReport - after controlWrite", 20,100); |
jmitc91516 | 0:47c880c1463d | 183 | |
jmitc91516 | 1:a5258871b33d | 184 | #ifdef ALLOW_DEBUG_PRINTS_HERE |
jmitc91516 | 1:a5258871b33d | 185 | SpecialDebugPrint("SetDeviceReport - waiting for response", 20,120); |
jmitc91516 | 1:a5258871b33d | 186 | #endif |
jmitc91516 | 1:a5258871b33d | 187 | |
jmitc91516 | 0:47c880c1463d | 188 | while (!responseReceived) { |
jmitc91516 | 0:47c880c1463d | 189 | // wait... |
jmitc91516 | 1:a5258871b33d | 190 | Thread::wait(10); // *** With this, we can successfully call this function from the Ethernet thread *** |
jmitc91516 | 1:a5258871b33d | 191 | // (without it, this function enters an infinite loop at this point when called |
jmitc91516 | 1:a5258871b33d | 192 | // from the Ethernet thread, although it is OK from the main thread) |
jmitc91516 | 0:47c880c1463d | 193 | } |
jmitc91516 | 0:47c880c1463d | 194 | |
jmitc91516 | 1:a5258871b33d | 195 | #ifdef ALLOW_DEBUG_PRINTS_HERE |
jmitc91516 | 1:a5258871b33d | 196 | SpecialDebugPrint("SetDeviceReport - after wait for response", 20,120); |
jmitc91516 | 1:a5258871b33d | 197 | #endif |
jmitc91516 | 1:a5258871b33d | 198 | |
jmitc91516 | 0:47c880c1463d | 199 | // RXHandler has now received the response - return it to the caller |
jmitc91516 | 0:47c880c1463d | 200 | |
jmitc91516 | 0:47c880c1463d | 201 | for (i = 0; i < GC_MESSAGE_LENGTH; ++i) { |
jmitc91516 | 0:47c880c1463d | 202 | response[i] = reportBuffer[i]; |
jmitc91516 | 0:47c880c1463d | 203 | } |
jmitc91516 | 0:47c880c1463d | 204 | response[i] = '\0'; |
jmitc91516 | 0:47c880c1463d | 205 | |
jmitc91516 | 0:47c880c1463d | 206 | alreadyInSetDeviceReport = false; |
jmitc91516 | 0:47c880c1463d | 207 | |
jmitc91516 | 0:47c880c1463d | 208 | return t; |
jmitc91516 | 0:47c880c1463d | 209 | } |
jmitc91516 | 0:47c880c1463d | 210 | |
jmitc91516 | 0:47c880c1463d | 211 | // Part of IUSBEnumerator interface |
jmitc91516 | 0:47c880c1463d | 212 | /* virtual */ void USBHostGC::setVidPid(uint16_t vid, uint16_t pid) |
jmitc91516 | 0:47c880c1463d | 213 | { |
jmitc91516 | 0:47c880c1463d | 214 | char buff[100]; |
jmitc91516 | 0:47c880c1463d | 215 | sprintf(buff, "setVidPid(%d %X, %d %X)\n", vid, vid, pid, pid); |
jmitc91516 | 0:47c880c1463d | 216 | DebugPrint(buff); |
jmitc91516 | 0:47c880c1463d | 217 | |
jmitc91516 | 1:a5258871b33d | 218 | deviceIsGC = ((vid == GC_VENDOR_ID) && ((pid == GC_PRODUCT_ID) || (pid == GC_PRODUCT_ID_2))); |
jmitc91516 | 0:47c880c1463d | 219 | |
jmitc91516 | 0:47c880c1463d | 220 | DebugPrint(deviceIsGC ? "Device is a GC\n" : "Device is *not* a GC\n"); |
jmitc91516 | 0:47c880c1463d | 221 | } |
jmitc91516 | 0:47c880c1463d | 222 | |
jmitc91516 | 0:47c880c1463d | 223 | // Part of IUSBEnumerator interface - must return true if the interface should be parsed |
jmitc91516 | 0:47c880c1463d | 224 | /* virtual */ bool USBHostGC::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) |
jmitc91516 | 0:47c880c1463d | 225 | { |
jmitc91516 | 0:47c880c1463d | 226 | char buff[100]; |
jmitc91516 | 0:47c880c1463d | 227 | 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); |
jmitc91516 | 0:47c880c1463d | 228 | DebugPrint(buff); |
jmitc91516 | 0:47c880c1463d | 229 | |
jmitc91516 | 0:47c880c1463d | 230 | // setVidPid should have been called before this - |
jmitc91516 | 0:47c880c1463d | 231 | // assume it will have identified whether or not the device is a GC |
jmitc91516 | 0:47c880c1463d | 232 | if (deviceIsGC) { |
jmitc91516 | 0:47c880c1463d | 233 | if ((intfGC == -1) && |
jmitc91516 | 0:47c880c1463d | 234 | (intf_class == HID_CLASS)) { |
jmitc91516 | 0:47c880c1463d | 235 | // Don't care about subclass and protocol in this case |
jmitc91516 | 0:47c880c1463d | 236 | |
jmitc91516 | 0:47c880c1463d | 237 | intfGC = intf_nb; |
jmitc91516 | 0:47c880c1463d | 238 | DebugPrint(" **** GC found **** \n"); |
jmitc91516 | 0:47c880c1463d | 239 | } |
jmitc91516 | 0:47c880c1463d | 240 | DebugPrint("GC found - parseInterface returning true\n"); |
jmitc91516 | 0:47c880c1463d | 241 | return true; |
jmitc91516 | 0:47c880c1463d | 242 | } |
jmitc91516 | 0:47c880c1463d | 243 | |
jmitc91516 | 0:47c880c1463d | 244 | DebugPrint("No GC found - parseInterface returning false\n"); |
jmitc91516 | 0:47c880c1463d | 245 | return false; |
jmitc91516 | 0:47c880c1463d | 246 | } |
jmitc91516 | 0:47c880c1463d | 247 | |
jmitc91516 | 0:47c880c1463d | 248 | // Part of IUSBEnumerator interface - must return true if the endpoint will be used |
jmitc91516 | 0:47c880c1463d | 249 | /* virtual */ bool USBHostGC::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) |
jmitc91516 | 0:47c880c1463d | 250 | { |
jmitc91516 | 0:47c880c1463d | 251 | char buff[100]; |
jmitc91516 | 0:47c880c1463d | 252 | sprintf(buff, "useEndPoint(%d %X, %d %X, %d %X)\n", intf_nb, intf_nb, type, type, dir, dir); |
jmitc91516 | 0:47c880c1463d | 253 | DebugPrint(buff); |
jmitc91516 | 0:47c880c1463d | 254 | |
jmitc91516 | 0:47c880c1463d | 255 | if (deviceIsGC) { |
jmitc91516 | 0:47c880c1463d | 256 | if ((intfGC == intf_nb) && |
jmitc91516 | 0:47c880c1463d | 257 | (type == INTERRUPT_ENDPOINT) && |
jmitc91516 | 0:47c880c1463d | 258 | (dir == IN)) { |
jmitc91516 | 0:47c880c1463d | 259 | DebugPrint("GC endpoint found - useEndPoint returning true\n"); |
jmitc91516 | 0:47c880c1463d | 260 | return true; |
jmitc91516 | 0:47c880c1463d | 261 | } |
jmitc91516 | 0:47c880c1463d | 262 | } |
jmitc91516 | 0:47c880c1463d | 263 | |
jmitc91516 | 0:47c880c1463d | 264 | // 'else' |
jmitc91516 | 0:47c880c1463d | 265 | DebugPrint("GC endpoint not found - useEndpoint returning false\n"); |
jmitc91516 | 0:47c880c1463d | 266 | return false; |
jmitc91516 | 0:47c880c1463d | 267 | } |