usb device

Committer:
ppo
Date:
Sat May 14 17:24:10 2022 +0000
Revision:
0:c1e89c49eae5
commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ppo 0:c1e89c49eae5 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
ppo 0:c1e89c49eae5 2 *
ppo 0:c1e89c49eae5 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
ppo 0:c1e89c49eae5 4 * and associated documentation files (the "Software"), to deal in the Software without
ppo 0:c1e89c49eae5 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
ppo 0:c1e89c49eae5 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
ppo 0:c1e89c49eae5 7 * Software is furnished to do so, subject to the following conditions:
ppo 0:c1e89c49eae5 8 *
ppo 0:c1e89c49eae5 9 * The above copyright notice and this permission notice shall be included in all copies or
ppo 0:c1e89c49eae5 10 * substantial portions of the Software.
ppo 0:c1e89c49eae5 11 *
ppo 0:c1e89c49eae5 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
ppo 0:c1e89c49eae5 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ppo 0:c1e89c49eae5 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
ppo 0:c1e89c49eae5 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
ppo 0:c1e89c49eae5 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ppo 0:c1e89c49eae5 17 */
ppo 0:c1e89c49eae5 18
ppo 0:c1e89c49eae5 19 #include "stdint.h"
ppo 0:c1e89c49eae5 20 #include "USBHAL.h"
ppo 0:c1e89c49eae5 21 #include "USBHID.h"
ppo 0:c1e89c49eae5 22
ppo 0:c1e89c49eae5 23
ppo 0:c1e89c49eae5 24 USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect): USBDevice(vendor_id, product_id, product_release)
ppo 0:c1e89c49eae5 25 {
ppo 0:c1e89c49eae5 26 output_length = output_report_length;
ppo 0:c1e89c49eae5 27 input_length = input_report_length;
ppo 0:c1e89c49eae5 28 if(connect) {
ppo 0:c1e89c49eae5 29 USBDevice::connect();
ppo 0:c1e89c49eae5 30 }
ppo 0:c1e89c49eae5 31 }
ppo 0:c1e89c49eae5 32
ppo 0:c1e89c49eae5 33
ppo 0:c1e89c49eae5 34 bool USBHID::send(HID_REPORT *report)
ppo 0:c1e89c49eae5 35 {
ppo 0:c1e89c49eae5 36 return write(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
ppo 0:c1e89c49eae5 37 }
ppo 0:c1e89c49eae5 38
ppo 0:c1e89c49eae5 39 bool USBHID::sendNB(HID_REPORT *report)
ppo 0:c1e89c49eae5 40 {
ppo 0:c1e89c49eae5 41 return writeNB(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
ppo 0:c1e89c49eae5 42 }
ppo 0:c1e89c49eae5 43
ppo 0:c1e89c49eae5 44
ppo 0:c1e89c49eae5 45 bool USBHID::read(HID_REPORT *report)
ppo 0:c1e89c49eae5 46 {
ppo 0:c1e89c49eae5 47 uint32_t bytesRead = 0;
ppo 0:c1e89c49eae5 48 bool result;
ppo 0:c1e89c49eae5 49 result = USBDevice::readEP(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
ppo 0:c1e89c49eae5 50 if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
ppo 0:c1e89c49eae5 51 return false;
ppo 0:c1e89c49eae5 52 report->length = bytesRead;
ppo 0:c1e89c49eae5 53 return result;
ppo 0:c1e89c49eae5 54 }
ppo 0:c1e89c49eae5 55
ppo 0:c1e89c49eae5 56
ppo 0:c1e89c49eae5 57 bool USBHID::readNB(HID_REPORT *report)
ppo 0:c1e89c49eae5 58 {
ppo 0:c1e89c49eae5 59 uint32_t bytesRead = 0;
ppo 0:c1e89c49eae5 60 bool result;
ppo 0:c1e89c49eae5 61 result = USBDevice::readEP_NB(EPINT_OUT, report->data, &bytesRead, MAX_HID_REPORT_SIZE);
ppo 0:c1e89c49eae5 62 report->length = bytesRead;
ppo 0:c1e89c49eae5 63 if(!readStart(EPINT_OUT, MAX_HID_REPORT_SIZE))
ppo 0:c1e89c49eae5 64 return false;
ppo 0:c1e89c49eae5 65 return result;
ppo 0:c1e89c49eae5 66 }
ppo 0:c1e89c49eae5 67
ppo 0:c1e89c49eae5 68
ppo 0:c1e89c49eae5 69 uint16_t USBHID::reportDescLength() {
ppo 0:c1e89c49eae5 70 reportDesc();
ppo 0:c1e89c49eae5 71 return reportLength;
ppo 0:c1e89c49eae5 72 }
ppo 0:c1e89c49eae5 73
ppo 0:c1e89c49eae5 74
ppo 0:c1e89c49eae5 75
ppo 0:c1e89c49eae5 76 //
ppo 0:c1e89c49eae5 77 // Route callbacks from lower layers to class(es)
ppo 0:c1e89c49eae5 78 //
ppo 0:c1e89c49eae5 79
ppo 0:c1e89c49eae5 80
ppo 0:c1e89c49eae5 81 // Called in ISR context
ppo 0:c1e89c49eae5 82 // Called by USBDevice on Endpoint0 request
ppo 0:c1e89c49eae5 83 // This is used to handle extensions to standard requests
ppo 0:c1e89c49eae5 84 // and class specific requests
ppo 0:c1e89c49eae5 85 // Return true if class handles this request
ppo 0:c1e89c49eae5 86 bool USBHID::USBCallback_request() {
ppo 0:c1e89c49eae5 87 bool success = false;
ppo 0:c1e89c49eae5 88 CONTROL_TRANSFER * transfer = getTransferPtr();
ppo 0:c1e89c49eae5 89 uint8_t *hidDescriptor;
ppo 0:c1e89c49eae5 90
ppo 0:c1e89c49eae5 91 // Process additional standard requests
ppo 0:c1e89c49eae5 92
ppo 0:c1e89c49eae5 93 if ((transfer->setup.bmRequestType.Type == STANDARD_TYPE))
ppo 0:c1e89c49eae5 94 {
ppo 0:c1e89c49eae5 95 switch (transfer->setup.bRequest)
ppo 0:c1e89c49eae5 96 {
ppo 0:c1e89c49eae5 97 case GET_DESCRIPTOR:
ppo 0:c1e89c49eae5 98 switch (DESCRIPTOR_TYPE(transfer->setup.wValue))
ppo 0:c1e89c49eae5 99 {
ppo 0:c1e89c49eae5 100 case REPORT_DESCRIPTOR:
ppo 0:c1e89c49eae5 101 if ((reportDesc() != NULL) \
ppo 0:c1e89c49eae5 102 && (reportDescLength() != 0))
ppo 0:c1e89c49eae5 103 {
ppo 0:c1e89c49eae5 104 transfer->remaining = reportDescLength();
ppo 0:c1e89c49eae5 105 transfer->ptr = reportDesc();
ppo 0:c1e89c49eae5 106 transfer->direction = DEVICE_TO_HOST;
ppo 0:c1e89c49eae5 107 success = true;
ppo 0:c1e89c49eae5 108 }
ppo 0:c1e89c49eae5 109 break;
ppo 0:c1e89c49eae5 110 case HID_DESCRIPTOR:
ppo 0:c1e89c49eae5 111 // Find the HID descriptor, after the configuration descriptor
ppo 0:c1e89c49eae5 112 hidDescriptor = findDescriptor(HID_DESCRIPTOR);
ppo 0:c1e89c49eae5 113 if (hidDescriptor != NULL)
ppo 0:c1e89c49eae5 114 {
ppo 0:c1e89c49eae5 115 transfer->remaining = HID_DESCRIPTOR_LENGTH;
ppo 0:c1e89c49eae5 116 transfer->ptr = hidDescriptor;
ppo 0:c1e89c49eae5 117 transfer->direction = DEVICE_TO_HOST;
ppo 0:c1e89c49eae5 118 success = true;
ppo 0:c1e89c49eae5 119 }
ppo 0:c1e89c49eae5 120 break;
ppo 0:c1e89c49eae5 121
ppo 0:c1e89c49eae5 122 default:
ppo 0:c1e89c49eae5 123 break;
ppo 0:c1e89c49eae5 124 }
ppo 0:c1e89c49eae5 125 break;
ppo 0:c1e89c49eae5 126 default:
ppo 0:c1e89c49eae5 127 break;
ppo 0:c1e89c49eae5 128 }
ppo 0:c1e89c49eae5 129 }
ppo 0:c1e89c49eae5 130
ppo 0:c1e89c49eae5 131 // Process class-specific requests
ppo 0:c1e89c49eae5 132
ppo 0:c1e89c49eae5 133 if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
ppo 0:c1e89c49eae5 134 {
ppo 0:c1e89c49eae5 135 switch (transfer->setup.bRequest)
ppo 0:c1e89c49eae5 136 {
ppo 0:c1e89c49eae5 137 case SET_REPORT:
ppo 0:c1e89c49eae5 138 // First byte will be used for report ID
ppo 0:c1e89c49eae5 139 outputReport.data[0] = transfer->setup.wValue & 0xff;
ppo 0:c1e89c49eae5 140 outputReport.length = transfer->setup.wLength + 1;
ppo 0:c1e89c49eae5 141
ppo 0:c1e89c49eae5 142 transfer->remaining = sizeof(outputReport.data) - 1;
ppo 0:c1e89c49eae5 143 transfer->ptr = &outputReport.data[1];
ppo 0:c1e89c49eae5 144 transfer->direction = HOST_TO_DEVICE;
ppo 0:c1e89c49eae5 145 transfer->notify = true;
ppo 0:c1e89c49eae5 146 success = true;
ppo 0:c1e89c49eae5 147 default:
ppo 0:c1e89c49eae5 148 break;
ppo 0:c1e89c49eae5 149 }
ppo 0:c1e89c49eae5 150 }
ppo 0:c1e89c49eae5 151
ppo 0:c1e89c49eae5 152 return success;
ppo 0:c1e89c49eae5 153 }
ppo 0:c1e89c49eae5 154
ppo 0:c1e89c49eae5 155
ppo 0:c1e89c49eae5 156 #define DEFAULT_CONFIGURATION (1)
ppo 0:c1e89c49eae5 157
ppo 0:c1e89c49eae5 158
ppo 0:c1e89c49eae5 159 // Called in ISR context
ppo 0:c1e89c49eae5 160 // Set configuration. Return false if the
ppo 0:c1e89c49eae5 161 // configuration is not supported
ppo 0:c1e89c49eae5 162 bool USBHID::USBCallback_setConfiguration(uint8_t configuration) {
ppo 0:c1e89c49eae5 163 if (configuration != DEFAULT_CONFIGURATION) {
ppo 0:c1e89c49eae5 164 return false;
ppo 0:c1e89c49eae5 165 }
ppo 0:c1e89c49eae5 166
ppo 0:c1e89c49eae5 167 // Configure endpoints > 0
ppo 0:c1e89c49eae5 168 addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
ppo 0:c1e89c49eae5 169 addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
ppo 0:c1e89c49eae5 170
ppo 0:c1e89c49eae5 171 // We activate the endpoint to be able to recceive data
ppo 0:c1e89c49eae5 172 readStart(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
ppo 0:c1e89c49eae5 173 return true;
ppo 0:c1e89c49eae5 174 }
ppo 0:c1e89c49eae5 175
ppo 0:c1e89c49eae5 176
ppo 0:c1e89c49eae5 177 uint8_t * USBHID::stringIinterfaceDesc() {
ppo 0:c1e89c49eae5 178 static uint8_t stringIinterfaceDescriptor[] = {
ppo 0:c1e89c49eae5 179 0x08, //bLength
ppo 0:c1e89c49eae5 180 STRING_DESCRIPTOR, //bDescriptorType 0x03
ppo 0:c1e89c49eae5 181 'H',0,'I',0,'D',0, //bString iInterface - HID
ppo 0:c1e89c49eae5 182 };
ppo 0:c1e89c49eae5 183 return stringIinterfaceDescriptor;
ppo 0:c1e89c49eae5 184 }
ppo 0:c1e89c49eae5 185
ppo 0:c1e89c49eae5 186 uint8_t * USBHID::stringIproductDesc() {
ppo 0:c1e89c49eae5 187 static uint8_t stringIproductDescriptor[] = {
ppo 0:c1e89c49eae5 188 0x16, //bLength
ppo 0:c1e89c49eae5 189 STRING_DESCRIPTOR, //bDescriptorType 0x03
ppo 0:c1e89c49eae5 190 'H',0,'I',0,'D',0,' ',0,'D',0,'E',0,'V',0,'I',0,'C',0,'E',0 //bString iProduct - HID device
ppo 0:c1e89c49eae5 191 };
ppo 0:c1e89c49eae5 192 return stringIproductDescriptor;
ppo 0:c1e89c49eae5 193 }
ppo 0:c1e89c49eae5 194
ppo 0:c1e89c49eae5 195
ppo 0:c1e89c49eae5 196
ppo 0:c1e89c49eae5 197 uint8_t * USBHID::reportDesc() {
ppo 0:c1e89c49eae5 198 static uint8_t reportDescriptor[] = {
ppo 0:c1e89c49eae5 199 0x06, LSB(0xFFAB), MSB(0xFFAB),
ppo 0:c1e89c49eae5 200 0x0A, LSB(0x0200), MSB(0x0200),
ppo 0:c1e89c49eae5 201 0xA1, 0x01, // Collection 0x01
ppo 0:c1e89c49eae5 202 0x75, 0x08, // report size = 8 bits
ppo 0:c1e89c49eae5 203 0x15, 0x00, // logical minimum = 0
ppo 0:c1e89c49eae5 204 0x26, 0xFF, 0x00, // logical maximum = 255
ppo 0:c1e89c49eae5 205 0x95, input_length, // report count
ppo 0:c1e89c49eae5 206 0x09, 0x01, // usage
ppo 0:c1e89c49eae5 207 0x81, 0x02, // Input (array)
ppo 0:c1e89c49eae5 208 0x95, output_length, // report count
ppo 0:c1e89c49eae5 209 0x09, 0x02, // usage
ppo 0:c1e89c49eae5 210 0x91, 0x02, // Output (array)
ppo 0:c1e89c49eae5 211 0xC0 // end collection
ppo 0:c1e89c49eae5 212
ppo 0:c1e89c49eae5 213 };
ppo 0:c1e89c49eae5 214 reportLength = sizeof(reportDescriptor);
ppo 0:c1e89c49eae5 215 return reportDescriptor;
ppo 0:c1e89c49eae5 216 }
ppo 0:c1e89c49eae5 217
ppo 0:c1e89c49eae5 218 #define DEFAULT_CONFIGURATION (1)
ppo 0:c1e89c49eae5 219 #define TOTAL_DESCRIPTOR_LENGTH ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) \
ppo 0:c1e89c49eae5 220 + (1 * INTERFACE_DESCRIPTOR_LENGTH) \
ppo 0:c1e89c49eae5 221 + (1 * HID_DESCRIPTOR_LENGTH) \
ppo 0:c1e89c49eae5 222 + (2 * ENDPOINT_DESCRIPTOR_LENGTH))
ppo 0:c1e89c49eae5 223
ppo 0:c1e89c49eae5 224 uint8_t * USBHID::configurationDesc() {
ppo 0:c1e89c49eae5 225 static uint8_t configurationDescriptor[] = {
ppo 0:c1e89c49eae5 226 CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
ppo 0:c1e89c49eae5 227 CONFIGURATION_DESCRIPTOR, // bDescriptorType
ppo 0:c1e89c49eae5 228 LSB(TOTAL_DESCRIPTOR_LENGTH), // wTotalLength (LSB)
ppo 0:c1e89c49eae5 229 MSB(TOTAL_DESCRIPTOR_LENGTH), // wTotalLength (MSB)
ppo 0:c1e89c49eae5 230 0x01, // bNumInterfaces
ppo 0:c1e89c49eae5 231 DEFAULT_CONFIGURATION, // bConfigurationValue
ppo 0:c1e89c49eae5 232 0x00, // iConfiguration
ppo 0:c1e89c49eae5 233 C_RESERVED | C_SELF_POWERED, // bmAttributes
ppo 0:c1e89c49eae5 234 C_POWER(0), // bMaxPower
ppo 0:c1e89c49eae5 235
ppo 0:c1e89c49eae5 236 INTERFACE_DESCRIPTOR_LENGTH, // bLength
ppo 0:c1e89c49eae5 237 INTERFACE_DESCRIPTOR, // bDescriptorType
ppo 0:c1e89c49eae5 238 0x00, // bInterfaceNumber
ppo 0:c1e89c49eae5 239 0x00, // bAlternateSetting
ppo 0:c1e89c49eae5 240 0x02, // bNumEndpoints
ppo 0:c1e89c49eae5 241 HID_CLASS, // bInterfaceClass
ppo 0:c1e89c49eae5 242 HID_SUBCLASS_NONE, // bInterfaceSubClass
ppo 0:c1e89c49eae5 243 HID_PROTOCOL_NONE, // bInterfaceProtocol
ppo 0:c1e89c49eae5 244 0x00, // iInterface
ppo 0:c1e89c49eae5 245
ppo 0:c1e89c49eae5 246 HID_DESCRIPTOR_LENGTH, // bLength
ppo 0:c1e89c49eae5 247 HID_DESCRIPTOR, // bDescriptorType
ppo 0:c1e89c49eae5 248 LSB(HID_VERSION_1_11), // bcdHID (LSB)
ppo 0:c1e89c49eae5 249 MSB(HID_VERSION_1_11), // bcdHID (MSB)
ppo 0:c1e89c49eae5 250 0x00, // bCountryCode
ppo 0:c1e89c49eae5 251 0x01, // bNumDescriptors
ppo 0:c1e89c49eae5 252 REPORT_DESCRIPTOR, // bDescriptorType
ppo 0:c1e89c49eae5 253 LSB(this->reportDescLength()), // wDescriptorLength (LSB)
ppo 0:c1e89c49eae5 254 MSB(this->reportDescLength()), // wDescriptorLength (MSB)
ppo 0:c1e89c49eae5 255
ppo 0:c1e89c49eae5 256 ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ppo 0:c1e89c49eae5 257 ENDPOINT_DESCRIPTOR, // bDescriptorType
ppo 0:c1e89c49eae5 258 PHY_TO_DESC(EPINT_IN), // bEndpointAddress
ppo 0:c1e89c49eae5 259 E_INTERRUPT, // bmAttributes
ppo 0:c1e89c49eae5 260 LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB)
ppo 0:c1e89c49eae5 261 MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB)
ppo 0:c1e89c49eae5 262 1, // bInterval (milliseconds)
ppo 0:c1e89c49eae5 263
ppo 0:c1e89c49eae5 264 ENDPOINT_DESCRIPTOR_LENGTH, // bLength
ppo 0:c1e89c49eae5 265 ENDPOINT_DESCRIPTOR, // bDescriptorType
ppo 0:c1e89c49eae5 266 PHY_TO_DESC(EPINT_OUT), // bEndpointAddress
ppo 0:c1e89c49eae5 267 E_INTERRUPT, // bmAttributes
ppo 0:c1e89c49eae5 268 LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB)
ppo 0:c1e89c49eae5 269 MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB)
ppo 0:c1e89c49eae5 270 1, // bInterval (milliseconds)
ppo 0:c1e89c49eae5 271 };
ppo 0:c1e89c49eae5 272 return configurationDescriptor;
ppo 0:c1e89c49eae5 273 }