Repository for import to local machine

Dependencies:   DMBasicGUI DMSupport

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?

UserRevisionLine numberNew 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 }