winusb_loop.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /* This file is the part of the Lightweight USB device Stack for STM32 microcontrollers
  2. *
  3. * Copyright ©2018 Travis Robinson <libusbdotnet[at]gmail[dot]com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. /* Includes ------------------------------------------------------------------*/
  16. #include "stm32f1xx_hal.h"
  17. #include <stdint.h>
  18. #include <stdbool.h>
  19. #include <string.h>
  20. #include "usb.h"
  21. #include "ms_os.h"
  22. #ifndef _STM32_WUSB_CONFIG_
  23. // YOUR VENDOR ID
  24. // http://pid.codes/1209/
  25. #define WUSB_VEND_ID 0x1209
  26. // YOUR PRODUCT ID
  27. #define WUSB_PROD_ID 0x0777
  28. // YOUR MANUFACTURER NAME
  29. #define WUSB_MANUFACTURER_STR "github.TravisRo"
  30. // YOUR PRODUCT NAME
  31. #define WUSB_PRODUCT_STR "WinUSB Communication Device"
  32. // YOUR DEVICE-INTERFACE-GUID
  33. // NOTE: A '\0' terminator is required! (This is a multi-sz field)
  34. #define WUSB_DEVICE_INTERFACE_GUID "{B7705C49-EAC6-4C73-AE94-ACAEF841D599}\0"
  35. #else
  36. #endif
  37. /////////////////////////////////// DEMO ENDPOINT SETUP ////////////////////////////////////
  38. #define WUSB_EP0_MAXPACKET_SIZE (8)
  39. #define WUSB_EP1_MAXPACKET_SIZE (64)
  40. #define WUSB_EP1_RX (0x01)
  41. #define WUSB_EP1_TX (0x82)
  42. //////////////////////////////////////// VARIABLES ////////////////////////////////////////
  43. // USB device
  44. usbd_device udev;
  45. // USB device buffer (buffer for ep0 rx requests [usbd_ctlreq])
  46. // 32 bytes gives us an extra 24 bytes for an incoming data payload.
  47. // This can bet set as low as 2! (8 bytes to hold the setup
  48. uint32_t wusb_control_buffer[8];
  49. // STM32CUBE RTC handle
  50. RTC_HandleTypeDef hrtc;
  51. // DEMO endpoint buffer for loopback
  52. uint8_t fifo[WUSB_EP1_MAXPACKET_SIZE * 4];
  53. uint32_t fpos = 0;
  54. ////////////////////////////////////// DEMO PROTOTYPES //////////////////////////////////////
  55. static void cdc_loopback(usbd_device* dev, uint8_t event, uint8_t ep);
  56. //////////////////////////////////////// DESCRIPTORS ////////////////////////////////////////
  57. struct winusb_config {
  58. struct usb_config_descriptor cfg;
  59. struct usb_interface_descriptor intf1;
  60. struct usb_endpoint_descriptor eprx1;
  61. struct usb_endpoint_descriptor eptx1;
  62. } __attribute__((packed));
  63. static const struct usb_device_descriptor device_desc = {
  64. .bLength = sizeof(struct usb_device_descriptor),
  65. .bDescriptorType = USB_DTYPE_DEVICE,
  66. .bcdUSB = VERSION_BCD(2, 0, 0),
  67. .bDeviceClass = USB_CLASS_PER_INTERFACE,
  68. .bDeviceSubClass = USB_SUBCLASS_NONE,
  69. .bDeviceProtocol = USB_PROTO_NONE,
  70. .bMaxPacketSize0 = 8,
  71. .idVendor = WUSB_VEND_ID,
  72. .idProduct = WUSB_PROD_ID,
  73. .bcdDevice = VERSION_BCD(1, 0, 0),
  74. .iManufacturer = 1,
  75. .iProduct = 2,
  76. .iSerialNumber = INTSERIALNO_DESCRIPTOR,
  77. .bNumConfigurations = 1,
  78. };
  79. static const struct winusb_config config_desc = {
  80. .cfg = {
  81. .bLength = sizeof(struct usb_config_descriptor),
  82. .bDescriptorType = USB_DTYPE_CONFIGURATION,
  83. .wTotalLength = sizeof(struct winusb_config),
  84. .bNumInterfaces = 1,
  85. .bConfigurationValue = 1,
  86. .iConfiguration = NO_DESCRIPTOR,
  87. .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED,
  88. .bMaxPower = USB_CFG_POWER_MA(100),
  89. },
  90. .intf1 = {
  91. .bLength = sizeof(struct usb_interface_descriptor),
  92. .bDescriptorType = USB_DTYPE_INTERFACE,
  93. .bInterfaceNumber = 0,
  94. .bAlternateSetting = 0,
  95. .bNumEndpoints = 2,
  96. .bInterfaceClass = USB_CLASS_APP_SPEC,
  97. .bInterfaceSubClass = 0x01,
  98. .bInterfaceProtocol = 0x07,
  99. .iInterface = NO_DESCRIPTOR,
  100. },
  101. .eprx1 = {
  102. .bLength = sizeof(struct usb_endpoint_descriptor),
  103. .bDescriptorType = USB_DTYPE_ENDPOINT,
  104. .bEndpointAddress = WUSB_EP1_RX,
  105. .bmAttributes = USB_EPTYPE_BULK,
  106. .wMaxPacketSize = WUSB_EP1_MAXPACKET_SIZE,
  107. .bInterval = 0x00,
  108. },
  109. .eptx1 = {
  110. .bLength = sizeof(struct usb_endpoint_descriptor),
  111. .bDescriptorType = USB_DTYPE_ENDPOINT,
  112. .bEndpointAddress = WUSB_EP1_TX,
  113. .bmAttributes = USB_EPTYPE_BULK,
  114. .wMaxPacketSize = WUSB_EP1_MAXPACKET_SIZE,
  115. .bInterval = 0x00,
  116. },
  117. };
  118. #define MS_VENDOR_CODE 0x20
  119. static const struct usb_string_descriptor ms_os_desc = USB_STRING_DESC("MSFT100\x20");
  120. static const struct usb_string_descriptor lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US);
  121. static const struct usb_string_descriptor manuf_desc_en = USB_STRING_DESC(WUSB_MANUFACTURER_STR);
  122. static const struct usb_string_descriptor prod_desc_en = USB_STRING_DESC(WUSB_PRODUCT_STR);
  123. static const struct usb_string_descriptor*const dtable[] = {
  124. &lang_desc,
  125. &manuf_desc_en,
  126. &prod_desc_en,
  127. };
  128. static const struct wusb_devguid_extprop_feature_descriptor devguid_ext_prop_feature_desc = {
  129. .dwLength = sizeof(struct wusb_devguid_extprop_feature_descriptor),
  130. .bcdVersion = VERSION_BCD(1,0,0),
  131. .wIndex = 5,
  132. .wCount = 1,
  133. .dev_guid_property = {
  134. .dwPropertyLength = sizeof(struct wusb_devguid_property),
  135. .dwPropertyType = 7, // (7 = Unicode REG_MULTI_SZ)
  136. .wPropertyNameLength = 42,
  137. .wPropertyName = STRING_TO_WCHARS("DeviceInterfaceGUIDs"),
  138. .dwPropertyDataLength = 80,
  139. .wPropertyData = STRING_TO_WCHARS(WUSB_DEVICE_INTERFACE_GUID)
  140. }
  141. };
  142. static const struct ms_os_compatid_descriptor compatid_desc = {
  143. .dwLength = sizeof(struct ms_os_compatid_descriptor),
  144. .bcdVersion = VERSION_BCD(1,0,0),
  145. .wIndex = 4,
  146. .bCount = 1,
  147. ._reservedA = {0, 0, 0, 0, 0, 0, 0},
  148. .bInterfaceNumber = 0,
  149. ._reservedB = {0},
  150. .chCompatibleID = {'W', 'I', 'N', 'U', 'S', 'B', 0, 0},
  151. .chSubCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0},
  152. ._reservedC = {0, 0, 0, 0, 0, 0}
  153. };
  154. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. ///////////////////////////////////////////// USB Core callbacks //////////////////////////////////////////////
  156. static usbd_respond wusb_getdesc(usbd_ctlreq* req, void** address, uint16_t* length) {
  157. const uint8_t dtype = req->wValue >> 8;
  158. const uint8_t dnumber = req->wValue & 0xFF;
  159. const void* desc;
  160. uint16_t len = 0;
  161. switch (dtype) {
  162. case USB_DTYPE_DEVICE:
  163. desc = &device_desc;
  164. break;
  165. case USB_DTYPE_CONFIGURATION:
  166. desc = &config_desc;
  167. len = sizeof(config_desc);
  168. break;
  169. case USB_DTYPE_STRING:
  170. if (dnumber < 3) {
  171. desc = dtable[dnumber];
  172. }
  173. else if (dnumber == 0xEE) {
  174. // Microsoft OS String Descriptor
  175. desc = &ms_os_desc;
  176. /* MSDN NOTES
  177. After the operating system requests a Microsoft OS String Descriptor from a device, it creates the following registry key:
  178. HLKM\SYSTEM\CurrentControlSet\Control\UsbFlags\*vvvvpppprrrrr*
  179. The operating system creates a registry entry, named osvc, under this registry key that indicates whether the device supports
  180. Microsoft OS Descriptors. If the device does not provide a valid response the first time that the operating system queries it
  181. for a Microsoft OS String Descriptor, the operating system will make no further requests for that descriptor.
  182. [TR] Once it gets a successful enuration, it will make no further requests for it PERIOD.
  183. [TR] You can change bcdDevice in the device descriptor to get a re-request or delete the UsbFlags key for your dev.
  184. */
  185. }
  186. else {
  187. return usbd_fail;
  188. }
  189. break;
  190. default:
  191. return usbd_fail;
  192. }
  193. if (len == 0) {
  194. len = ((struct usb_header_descriptor*)desc)->bLength;
  195. }
  196. *address = (void*)desc;
  197. *length = len;
  198. return usbd_ack;
  199. }
  200. static usbd_respond wusb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
  201. if ((req->bmRequestType == (USB_REQ_DEVTOHOST | USB_REQ_VENDOR | USB_REQ_DEVICE)) ||
  202. (req->bmRequestType == (USB_REQ_DEVTOHOST | USB_REQ_VENDOR | USB_REQ_INTERFACE))) {
  203. if (req->bRequest == MS_VENDOR_CODE) {
  204. switch (req->wIndex) {
  205. case 0x04: // Compatible ID Feature Descriptor
  206. // NOTE: data_ptr and data_count are the same as the address and length params
  207. // in the get descriptor request.
  208. dev->status.data_ptr = (void*)&compatid_desc;
  209. dev->status.data_count = sizeof(compatid_desc);
  210. return usbd_ack;
  211. case 0x05: // Microsoft Extended Properties Feature Descriptor
  212. dev->status.data_ptr = (void*)&devguid_ext_prop_feature_desc;
  213. dev->status.data_count = sizeof(devguid_ext_prop_feature_desc);
  214. return usbd_ack;
  215. default: ;
  216. }
  217. }
  218. }
  219. return usbd_fail;
  220. }
  221. static usbd_respond wusb_setconf(usbd_device* dev, uint8_t cfg) {
  222. switch (cfg) {
  223. case 0:
  224. /* deconfiguring device */
  225. usbd_ep_deconfig(dev, WUSB_EP1_TX);
  226. usbd_ep_deconfig(dev, WUSB_EP1_RX);
  227. usbd_reg_endpoint(dev, WUSB_EP1_RX, 0);
  228. usbd_reg_endpoint(dev, WUSB_EP1_TX, 0);
  229. return usbd_ack;
  230. case 1:
  231. /* configuring device */
  232. usbd_ep_config(dev, WUSB_EP1_RX, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, WUSB_EP1_MAXPACKET_SIZE);
  233. usbd_ep_config(dev, WUSB_EP1_TX, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, WUSB_EP1_MAXPACKET_SIZE);
  234. usbd_reg_endpoint(dev, WUSB_EP1_RX, cdc_loopback);
  235. usbd_reg_endpoint(dev, WUSB_EP1_TX, cdc_loopback);
  236. usbd_ep_write(dev, WUSB_EP1_TX, 0, 0);
  237. return usbd_ack;
  238. default:
  239. return usbd_fail;
  240. }
  241. }
  242. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. ////////////////////////////////////////////////// DEMO MAIN //////////////////////////////////////////////////
  244. static void cdc_loopback(usbd_device* dev, uint8_t event, uint8_t ep) {
  245. int _t;
  246. switch (event) {
  247. case usbd_evt_eptx:
  248. _t = usbd_ep_write(dev,
  249. WUSB_EP1_TX,
  250. &fifo[0],
  251. (fpos < WUSB_EP1_MAXPACKET_SIZE) ? fpos : WUSB_EP1_MAXPACKET_SIZE);
  252. if (_t > 0) {
  253. memmove(&fifo[0], &fifo[_t], fpos - _t);
  254. fpos -= _t;
  255. }
  256. case usbd_evt_eprx:
  257. if (fpos < (sizeof(fifo) - WUSB_EP1_MAXPACKET_SIZE)) {
  258. _t = usbd_ep_read(dev, WUSB_EP1_RX, &fifo[fpos], WUSB_EP1_MAXPACKET_SIZE);
  259. if (_t > 0) {
  260. fpos += _t;
  261. }
  262. }
  263. default:
  264. break;
  265. }
  266. }
  267. static void wusb_init_usbd(void) {
  268. usbd_init(&udev, &usbd_hw, WUSB_EP0_MAXPACKET_SIZE, wusb_control_buffer, sizeof(wusb_control_buffer));
  269. usbd_reg_config(&udev, wusb_setconf);
  270. usbd_reg_control(&udev, wusb_control);
  271. usbd_reg_descr(&udev, wusb_getdesc);
  272. }
  273. #if defined(WUSB_USE_IRQ)
  274. #if defined(STM32L052xx)
  275. #define USB_HANDLER USB_IRQHandler
  276. #define USB_NVIC_IRQ USB_IRQn
  277. #elif defined(STM32L100xC)
  278. #define USB_HANDLER USB_LP_IRQHandler
  279. #define USB_NVIC_IRQ USB_LP_IRQn
  280. #elif defined(STM32L476xx)
  281. #define USB_HANDLER OTG_FS_IRQHandler
  282. #define USB_NVIC_IRQ OTG_FS_IRQn
  283. #elif defined(STM32F103x6)
  284. #define USB_HANDLER USB_LP_CAN1_RX0_IRQHandler
  285. #define USB_NVIC_IRQ USB_LP_CAN1_RX0_IRQn
  286. #elif defined(STM32F103xE)
  287. #define USB_HANDLER USB_LP_CAN1_RX0_IRQHandler
  288. #define USB_NVIC_IRQ USB_LP_CAN1_RX0_IRQn
  289. #elif defined(STM32F429xx)
  290. #define USB_HANDLER OTG_FS_IRQHandler
  291. #define USB_NVIC_IRQ OTG_FS_IRQn
  292. #else
  293. #error Not supported
  294. #endif
  295. #endif
  296. void USB_HANDLER(void) {
  297. usbd_poll(&udev);
  298. }
  299. #ifdef CUBE_CALLS_MAIN
  300. void wusb_main(void) {
  301. #else
  302. void main(void) {
  303. #endif
  304. wusb_init_usbd();
  305. #ifdef USB_NVIC_IRQ
  306. NVIC_EnableIRQ(USB_NVIC_IRQ);
  307. #endif
  308. usbd_enable(&udev, true);
  309. usbd_connect(&udev, true);
  310. uint32_t curTick = HAL_GetTick();
  311. while (true) {
  312. #ifndef USB_NVIC_IRQ
  313. usbd_poll(&udev);
  314. #endif
  315. const uint32_t nextTick = HAL_GetTick();
  316. if (curTick + 1000 < nextTick) {
  317. curTick = nextTick;
  318. HAL_GPIO_TogglePin(LED_1_GPIO_Port, LED_1_Pin);
  319. }
  320. #ifdef USB_NVIC_IRQ
  321. __WFI();
  322. #endif
  323. }
  324. }