usb 2.0.0-alpha.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/.gitattributes +1 -0
  2. package/.gitmodules +1 -1
  3. package/CHANGELOG.md +91 -0
  4. package/README.md +570 -0
  5. package/binding.gyp +2 -2
  6. package/dist/index.d.ts +16 -5
  7. package/dist/index.js +135 -5
  8. package/dist/index.js.map +1 -1
  9. package/dist/usb/bindings.d.ts +13 -0
  10. package/dist/usb/bindings.js +2 -1
  11. package/dist/usb/bindings.js.map +1 -1
  12. package/dist/usb/index.d.ts +0 -2
  13. package/dist/usb/index.js +75 -112
  14. package/dist/usb/index.js.map +1 -1
  15. package/dist/usb/interface.js.map +1 -1
  16. package/dist/webusb/index.d.ts +28 -19
  17. package/dist/webusb/index.js +152 -66
  18. package/dist/webusb/index.js.map +1 -1
  19. package/dist/webusb/webusb-device.d.ts +1 -1
  20. package/dist/webusb/webusb-device.js +15 -6
  21. package/dist/webusb/webusb-device.js.map +1 -1
  22. package/libusb/.private/pre-commit.sh +7 -1
  23. package/libusb/.travis.yml +49 -0
  24. package/libusb/AUTHORS +44 -3
  25. package/libusb/Brewfile +4 -0
  26. package/libusb/ChangeLog +74 -2
  27. package/libusb/README.md +32 -0
  28. package/libusb/TODO +1 -1
  29. package/libusb/Xcode/common.xcconfig +12 -0
  30. package/libusb/Xcode/config.h +0 -3
  31. package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +959 -1
  32. package/libusb/android/README +4 -2
  33. package/libusb/android/config.h +0 -6
  34. package/libusb/appveyor.yml +41 -0
  35. package/libusb/appveyor_cygwin.bat +11 -0
  36. package/libusb/appveyor_minGW.bat +19 -0
  37. package/libusb/autogen.sh +1 -1
  38. package/libusb/bootstrap.sh +3 -16
  39. package/libusb/configure.ac +108 -80
  40. package/libusb/doc/doxygen.cfg.in +1785 -739
  41. package/libusb/examples/Makefile.am +1 -1
  42. package/libusb/examples/dpfp.c +3 -1
  43. package/libusb/examples/dpfp_threaded.c +23 -10
  44. package/libusb/examples/ezusb.c +3 -3
  45. package/libusb/examples/ezusb.h +2 -2
  46. package/libusb/examples/fxload.c +31 -9
  47. package/libusb/examples/hotplugtest.c +35 -7
  48. package/libusb/examples/listdevs.c +3 -1
  49. package/libusb/examples/sam3u_benchmark.c +3 -3
  50. package/libusb/examples/testlibusb.c +277 -0
  51. package/libusb/examples/xusb.c +40 -34
  52. package/libusb/libusb/Makefile.am +49 -23
  53. package/libusb/libusb/core.c +855 -457
  54. package/libusb/libusb/descriptor.c +72 -78
  55. package/libusb/libusb/hotplug.c +122 -76
  56. package/libusb/libusb/hotplug.h +42 -25
  57. package/libusb/libusb/io.c +625 -390
  58. package/libusb/libusb/libusb-1.0.def +12 -0
  59. package/libusb/libusb/libusb.h +218 -150
  60. package/libusb/libusb/libusbi.h +346 -176
  61. package/libusb/libusb/os/darwin_usb.c +604 -319
  62. package/libusb/libusb/os/darwin_usb.h +61 -20
  63. package/libusb/libusb/os/haiku_pollfs.cpp +367 -0
  64. package/libusb/libusb/os/haiku_usb.h +113 -0
  65. package/libusb/libusb/os/haiku_usb_backend.cpp +533 -0
  66. package/libusb/libusb/os/haiku_usb_raw.cpp +267 -0
  67. package/libusb/libusb/os/haiku_usb_raw.h +188 -0
  68. package/libusb/libusb/os/linux_netlink.c +186 -146
  69. package/libusb/libusb/os/linux_udev.c +36 -14
  70. package/libusb/libusb/os/linux_usbfs.c +426 -225
  71. package/libusb/libusb/os/linux_usbfs.h +5 -3
  72. package/libusb/libusb/os/netbsd_usb.c +21 -77
  73. package/libusb/libusb/os/openbsd_usb.c +32 -115
  74. package/libusb/libusb/os/poll_posix.c +38 -5
  75. package/libusb/libusb/os/poll_posix.h +3 -0
  76. package/libusb/libusb/os/poll_windows.c +277 -626
  77. package/libusb/libusb/os/poll_windows.h +11 -44
  78. package/libusb/libusb/os/sunos_usb.c +1695 -0
  79. package/libusb/libusb/os/sunos_usb.h +80 -0
  80. package/libusb/libusb/os/threads_posix.c +24 -26
  81. package/libusb/libusb/os/threads_posix.h +73 -21
  82. package/libusb/libusb/os/threads_windows.c +71 -157
  83. package/libusb/libusb/os/threads_windows.h +68 -44
  84. package/libusb/libusb/os/wince_usb.c +276 -420
  85. package/libusb/libusb/os/wince_usb.h +23 -28
  86. package/libusb/libusb/os/windows_common.h +78 -58
  87. package/libusb/libusb/os/windows_nt_common.c +1010 -0
  88. package/libusb/libusb/os/windows_nt_common.h +110 -0
  89. package/libusb/libusb/os/windows_nt_shared_types.h +147 -0
  90. package/libusb/libusb/os/windows_usbdk.c +830 -0
  91. package/libusb/libusb/os/windows_usbdk.h +103 -0
  92. package/libusb/libusb/os/windows_winusb.c +4391 -0
  93. package/libusb/libusb/os/windows_winusb.h +783 -0
  94. package/libusb/libusb/strerror.c +41 -7
  95. package/libusb/libusb/sync.c +41 -13
  96. package/libusb/libusb/version.h +1 -1
  97. package/libusb/libusb/version_nano.h +1 -1
  98. package/libusb/libusb-1.0.pc.in +1 -1
  99. package/libusb/msvc/appveyor.bat +27 -0
  100. package/libusb/msvc/config.h +5 -4
  101. package/libusb/msvc/ddk_build.cmd +87 -43
  102. package/libusb/msvc/fxload_2010.vcxproj +24 -104
  103. package/libusb/msvc/fxload_2012.vcxproj +24 -107
  104. package/libusb/msvc/fxload_2013.vcxproj +24 -107
  105. package/libusb/msvc/fxload_2015.vcxproj +91 -0
  106. package/libusb/msvc/fxload_2017.vcxproj +114 -0
  107. package/libusb/msvc/fxload_sources +1 -1
  108. package/libusb/msvc/getopt_2010.vcxproj +16 -75
  109. package/libusb/msvc/getopt_2012.vcxproj +16 -79
  110. package/libusb/msvc/getopt_2013.vcxproj +16 -79
  111. package/libusb/msvc/getopt_2015.vcxproj +73 -0
  112. package/libusb/msvc/getopt_2017.vcxproj +98 -0
  113. package/libusb/msvc/getopt_sources +6 -2
  114. package/libusb/msvc/hotplugtest_2010.vcxproj +18 -99
  115. package/libusb/msvc/hotplugtest_2012.vcxproj +18 -102
  116. package/libusb/msvc/hotplugtest_2013.vcxproj +18 -102
  117. package/libusb/msvc/hotplugtest_2015.vcxproj +83 -0
  118. package/libusb/msvc/hotplugtest_2017.vcxproj +106 -0
  119. package/libusb/msvc/hotplugtest_sources +1 -1
  120. package/libusb/msvc/libusb_2005.sln +20 -20
  121. package/libusb/msvc/libusb_2010.sln +57 -46
  122. package/libusb/msvc/libusb_2012.sln +57 -46
  123. package/libusb/msvc/libusb_2013.sln +57 -50
  124. package/libusb/msvc/libusb_2015.sln +59 -52
  125. package/libusb/msvc/libusb_2017.sln +186 -0
  126. package/libusb/msvc/libusb_dll.dsp +2 -2
  127. package/libusb/msvc/libusb_dll_2005.vcproj +30 -2
  128. package/libusb/msvc/libusb_dll_2010.vcxproj +26 -90
  129. package/libusb/msvc/libusb_dll_2012.vcxproj +28 -96
  130. package/libusb/msvc/libusb_dll_2013.vcxproj +28 -96
  131. package/libusb/msvc/libusb_dll_2015.vcxproj +107 -0
  132. package/libusb/msvc/libusb_dll_2017.vcxproj +134 -0
  133. package/libusb/msvc/libusb_dll_wince.vcproj +9 -1
  134. package/libusb/msvc/libusb_sources +10 -5
  135. package/libusb/msvc/libusb_static.dsp +2 -2
  136. package/libusb/msvc/libusb_static_2005.vcproj +32 -4
  137. package/libusb/msvc/libusb_static_2010.vcxproj +24 -83
  138. package/libusb/msvc/libusb_static_2012.vcxproj +25 -87
  139. package/libusb/msvc/libusb_static_2013.vcxproj +25 -87
  140. package/libusb/msvc/libusb_static_2015.vcxproj +98 -0
  141. package/libusb/msvc/libusb_static_2017.vcxproj +117 -0
  142. package/libusb/msvc/libusb_static_wince.vcproj +20 -26
  143. package/libusb/msvc/libusb_wince.sln +88 -88
  144. package/libusb/msvc/listdevs_2010.vcxproj +16 -99
  145. package/libusb/msvc/listdevs_2012.vcxproj +16 -102
  146. package/libusb/msvc/listdevs_2013.vcxproj +16 -102
  147. package/libusb/msvc/listdevs_2015.vcxproj +83 -0
  148. package/libusb/msvc/listdevs_2017.vcxproj +106 -0
  149. package/libusb/msvc/listdevs_sources +2 -1
  150. package/libusb/msvc/stress_2010.vcxproj +20 -101
  151. package/libusb/msvc/stress_2012.vcxproj +20 -104
  152. package/libusb/msvc/stress_2013.vcxproj +20 -104
  153. package/libusb/msvc/stress_2015.vcxproj +87 -0
  154. package/libusb/msvc/stress_2017.vcxproj +110 -0
  155. package/libusb/msvc/stress_sources +21 -0
  156. package/libusb/msvc/testlibusb_2010.vcxproj +82 -0
  157. package/libusb/msvc/testlibusb_2012.vcxproj +83 -0
  158. package/libusb/msvc/testlibusb_2013.vcxproj +83 -0
  159. package/libusb/msvc/testlibusb_2015.vcxproj +83 -0
  160. package/libusb/msvc/testlibusb_2017.vcxproj +106 -0
  161. package/libusb/msvc/testlibusb_sources +20 -0
  162. package/libusb/msvc/xusb_2010.vcxproj +17 -98
  163. package/libusb/msvc/xusb_2012.vcxproj +17 -101
  164. package/libusb/msvc/xusb_2013.vcxproj +17 -101
  165. package/libusb/msvc/xusb_2015.vcxproj +83 -0
  166. package/libusb/msvc/xusb_2017.vcxproj +106 -0
  167. package/libusb/msvc/xusb_sources +1 -1
  168. package/libusb/tests/stress.c +2 -2
  169. package/libusb/tests/testlib.c +0 -4
  170. package/libusb/travis-autogen.sh +39 -0
  171. package/libusb.gypi +13 -2
  172. package/package.json +23 -13
  173. package/prebuilds/android-arm/node.napi.armv7.node +0 -0
  174. package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
  175. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  176. package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
  177. package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
  178. package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
  179. package/prebuilds/linux-ia32/node.napi.node +0 -0
  180. package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
  181. package/prebuilds/linux-x64/node.napi.musl.node +0 -0
  182. package/prebuilds/win32-ia32/node.napi.node +0 -0
  183. package/prebuilds/win32-x64/node.napi.node +0 -0
  184. package/src/device.cc +7 -7
  185. package/src/node_usb.cc +43 -1
  186. package/src/node_usb.h +1 -0
  187. package/src/uv_async_queue.h +33 -25
  188. package/test/usb.coffee +12 -4
  189. package/tsc/index.ts +68 -8
  190. package/tsc/usb/bindings.ts +19 -1
  191. package/tsc/usb/index.ts +66 -68
  192. package/tsc/usb/interface.ts +2 -2
  193. package/tsc/webusb/index.ts +187 -75
  194. package/tsc/webusb/webusb-device.ts +28 -17
  195. package/.github/workflows/prebuild.yml +0 -48
  196. package/Readme.md +0 -339
  197. package/dist/webusb/typed-event-target.d.ts +0 -11
  198. package/dist/webusb/typed-event-target.js +0 -21
  199. package/dist/webusb/typed-event-target.js.map +0 -1
  200. package/docs/assets/css/main.css +0 -2660
  201. package/docs/assets/images/icons.png +0 -0
  202. package/docs/assets/images/icons@2x.png +0 -0
  203. package/docs/assets/images/widgets.png +0 -0
  204. package/docs/assets/images/widgets@2x.png +0 -0
  205. package/docs/assets/js/main.js +0 -248
  206. package/docs/assets/js/search.js +0 -1
  207. package/docs/classes/usb_bindings.device.html +0 -1338
  208. package/docs/classes/usb_bindings.libusbexception.html +0 -234
  209. package/docs/classes/usb_bindings.transfer.html +0 -344
  210. package/docs/classes/usb_capability.capability.html +0 -297
  211. package/docs/classes/usb_device.extendeddevice.html +0 -766
  212. package/docs/classes/usb_endpoint.endpoint.html +0 -472
  213. package/docs/classes/usb_endpoint.inendpoint.html +0 -766
  214. package/docs/classes/usb_endpoint.outendpoint.html +0 -582
  215. package/docs/classes/usb_interface.interface.html +0 -648
  216. package/docs/classes/webusb.webusb-1.html +0 -615
  217. package/docs/classes/webusb_mutex.mutex.html +0 -270
  218. package/docs/classes/webusb_typed_event_target.typedeventtarget.html +0 -443
  219. package/docs/classes/webusb_webusb_device.webusbdevice.html +0 -904
  220. package/docs/index.html +0 -500
  221. package/docs/interfaces/usb.deviceevents.html +0 -242
  222. package/docs/interfaces/usb_descriptors.bosdescriptor.html +0 -293
  223. package/docs/interfaces/usb_descriptors.capabilitydescriptor.html +0 -274
  224. package/docs/interfaces/usb_descriptors.configdescriptor.html +0 -388
  225. package/docs/interfaces/usb_descriptors.devicedescriptor.html +0 -464
  226. package/docs/interfaces/usb_descriptors.endpointdescriptor.html +0 -370
  227. package/docs/interfaces/usb_descriptors.interfacedescriptor.html +0 -407
  228. package/docs/interfaces/webusb.usboptions.html +0 -226
  229. package/docs/modules/index.html +0 -173
  230. package/docs/modules/usb.html +0 -173
  231. package/docs/modules/usb_bindings.html +0 -2319
  232. package/docs/modules/usb_capability.html +0 -156
  233. package/docs/modules/usb_descriptors.html +0 -176
  234. package/docs/modules/usb_device.html +0 -156
  235. package/docs/modules/usb_endpoint.html +0 -164
  236. package/docs/modules/usb_interface.html +0 -156
  237. package/docs/modules/webusb.html +0 -165
  238. package/docs/modules/webusb_mutex.html +0 -156
  239. package/docs/modules/webusb_typed_event_target.html +0 -156
  240. package/docs/modules/webusb_webusb_device.html +0 -156
  241. package/docs/modules.html +0 -156
  242. package/libusb/INSTALL +0 -234
  243. package/libusb/README +0 -28
  244. package/libusb/libusb/os/windows_usb.c +0 -5347
  245. package/libusb/libusb/os/windows_usb.h +0 -971
  246. package/libusb/msvc/fxload_2010.vcxproj.filters +0 -25
  247. package/libusb/msvc/fxload_2012.vcxproj.filters +0 -25
  248. package/libusb/msvc/getopt_2010.vcxproj.filters +0 -26
  249. package/libusb/msvc/getopt_2012.vcxproj.filters +0 -26
  250. package/libusb/msvc/hotplugtest_2010.vcxproj.filters +0 -14
  251. package/libusb/msvc/hotplugtest_2012.vcxproj.filters +0 -14
  252. package/libusb/msvc/libusb_dll_2010.vcxproj.filters +0 -81
  253. package/libusb/msvc/libusb_dll_2012.vcxproj.filters +0 -84
  254. package/libusb/msvc/libusb_static_2010.vcxproj.filters +0 -74
  255. package/libusb/msvc/libusb_static_2012.vcxproj.filters +0 -74
  256. package/libusb/msvc/listdevs_2010.vcxproj.filters +0 -14
  257. package/libusb/msvc/listdevs_2012.vcxproj.filters +0 -14
  258. package/libusb/msvc/stress_2010.vcxproj.filters +0 -25
  259. package/libusb/msvc/stress_2012.vcxproj.filters +0 -25
  260. package/libusb/msvc/xusb_2010.vcxproj.filters +0 -14
  261. package/libusb/msvc/xusb_2012.vcxproj.filters +0 -14
  262. package/tsc/webusb/typed-event-target.ts +0 -23
package/package.json CHANGED
@@ -2,14 +2,14 @@
2
2
  "name": "usb",
3
3
  "description": "Library to access USB devices",
4
4
  "license": "MIT",
5
- "version": "2.0.0-alpha.1",
5
+ "version": "2.0.3",
6
6
  "main": "dist/index.js",
7
7
  "engines": {
8
- "node": ">=10"
8
+ "node": ">=10.16.0"
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "https://github.com/tessel/node-usb.git"
12
+ "url": "https://github.com/node-usb/node-usb.git"
13
13
  },
14
14
  "contributors": [
15
15
  {
@@ -37,22 +37,29 @@
37
37
  ],
38
38
  "scripts": {
39
39
  "prepare": "yarn compile",
40
- "install": "prebuild-install --runtime napi --verbose || node-gyp rebuild",
41
- "prebuild": "prebuild --runtime napi -t 4 --force --strip --verbose",
40
+ "install": "node-gyp-build",
42
41
  "clean": "git clean -dfx",
43
42
  "compile": "tsc && yarn lint && yarn docs",
44
43
  "lint": "eslint . --ext .ts",
45
44
  "watch": "tsc -w --preserveWatchOutput",
46
45
  "test": "mocha --require coffeescript/register --grep Module test/*",
47
46
  "full-test": "mocha --require coffeescript/register test/*.coffee",
48
- "valgrind": "coffee -c test/usb.coffee; valgrind --leak-check=full --show-possibly-lost=no node --expose-gc --trace-gc node_modules/mocha/bin/_mocha -R spec",
49
- "docs": "typedoc"
47
+ "valgrind": "coffee -c test/*.coffee; valgrind --leak-check=full --show-possibly-lost=no node --expose-gc --trace-gc node_modules/mocha/bin/_mocha -R spec",
48
+ "docs": "typedoc",
49
+ "prebuild": "prebuildify --napi --target 10.16.0 --strip",
50
+ "prebuild-darwin": "prebuildify --napi --target 10.16.0 --strip --arch x64+arm64",
51
+ "prebuild-win32-x86": "prebuildify --napi --target 10.16.0 --strip",
52
+ "prebuild-win32-x64": "prebuildify --napi --target 10.16.0 --strip",
53
+ "prebuild-linux-x86": "prebuildify-cross -i ghcr.io/node-usb/linux-x86 --napi --target 10.16.0 --strip",
54
+ "prebuild-linux-x64": "prebuildify-cross -i ghcr.io/node-usb/centos7-devtoolset7 -i ghcr.io/node-usb/alpine --napi --target 10.16.0 --strip --tag-libc",
55
+ "prebuild-linux-arm": "prebuildify-cross -i ghcr.io/node-usb/linux-arm64 -i ghcr.io/node-usb/linux-armv7 -i ghcr.io/node-usb/linux-armv6 --napi --target 10.16.0 --strip --tag-armv",
56
+ "prebuild-android-arm": "prebuildify-cross -i ghcr.io/node-usb/android-arm64 -i ghcr.io/node-usb/android-armv7 --napi --target 10.16.0 --strip --tag-armv",
57
+ "prebuild-download": "prebuildify-ci download"
50
58
  },
51
59
  "dependencies": {
52
60
  "@types/w3c-web-usb": "^1.0.4",
53
- "bindings": "^1.4.0",
54
- "node-addon-api": "^3.1.0",
55
- "prebuild-install": "^6.1.1"
61
+ "node-addon-api": "^4.2.0",
62
+ "node-gyp-build": "^4.3.0"
56
63
  },
57
64
  "devDependencies": {
58
65
  "@types/node": "^14.14.41",
@@ -60,9 +67,12 @@
60
67
  "@typescript-eslint/parser": "^4.28.0",
61
68
  "coffeescript": "^2.5.1",
62
69
  "eslint": "^7.29.0",
63
- "mocha": "^8.3.2",
64
- "prebuild": "^10.0.1",
65
- "typedoc": "^0.20.36",
70
+ "mocha": "^9.1.3",
71
+ "node-gyp": "^7.1.2",
72
+ "prebuildify": "^4.2.1",
73
+ "prebuildify-ci": "^1.0.5",
74
+ "prebuildify-cross": "^4.0.1",
75
+ "typedoc": "^0.22.10",
66
76
  "typescript": "~4.2.4"
67
77
  },
68
78
  "binary": {
package/src/device.cc CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
  Napi::FunctionReference Device::constructor;
13
13
 
14
- Device::Device(const Napi::CallbackInfo & info) : Napi::ObjectWrap<Device>(info), device_handle(0), refs_(1)
14
+ Device::Device(const Napi::CallbackInfo & info) : Napi::ObjectWrap<Device>(info), device_handle(0), refs_(0)
15
15
  #ifndef USE_POLL
16
16
  , completionQueue(handleCompletion)
17
17
  #endif
@@ -19,18 +19,12 @@ Device::Device(const Napi::CallbackInfo & info) : Napi::ObjectWrap<Device>(info)
19
19
  device = info[0].As<Napi::External<libusb_device>>().Data();
20
20
  libusb_ref_device(device);
21
21
  byPtr.insert(std::make_pair(device, this));
22
- #ifndef USE_POLL
23
- completionQueue.start(info.Env());
24
- #endif
25
22
  DEBUG_LOG("Created device %p", this);
26
23
  Constructor(info);
27
24
  }
28
25
 
29
26
  Device::~Device(){
30
27
  DEBUG_LOG("Freed device %p", this);
31
- #ifndef USE_POLL
32
- completionQueue.stop();
33
- #endif
34
28
  byPtr.erase(device);
35
29
  libusb_close(device_handle);
36
30
  libusb_unref_device(device);
@@ -194,6 +188,9 @@ Napi::Value Device::Open(const Napi::CallbackInfo& info) {
194
188
  ENTER_METHOD(Device, 0);
195
189
  if (!self->device_handle){
196
190
  CHECK_USB(libusb_open(self->device, &self->device_handle));
191
+ #ifndef USE_POLL
192
+ completionQueue.start(info.Env());
193
+ #endif
197
194
  }
198
195
  return env.Undefined();
199
196
  }
@@ -203,6 +200,9 @@ Napi::Value Device::Close(const Napi::CallbackInfo& info) {
203
200
  if (self->canClose()){
204
201
  libusb_close(self->device_handle);
205
202
  self->device_handle = NULL;
203
+ #ifndef USE_POLL
204
+ completionQueue.stop();
205
+ #endif
206
206
  }else{
207
207
  THROW_ERROR("Can't close device with a pending request");
208
208
  }
package/src/node_usb.cc CHANGED
@@ -4,8 +4,11 @@
4
4
 
5
5
  Napi::Value SetDebugLevel(const Napi::CallbackInfo& info);
6
6
  Napi::Value GetDeviceList(const Napi::CallbackInfo& info);
7
+ Napi::Value GetLibusbCapability(const Napi::CallbackInfo& info);
7
8
  Napi::Value EnableHotplugEvents(const Napi::CallbackInfo& info);
8
9
  Napi::Value DisableHotplugEvents(const Napi::CallbackInfo& info);
10
+ Napi::Value RefHotplugEvents(const Napi::CallbackInfo& info);
11
+ Napi::Value UnrefHotplugEvents(const Napi::CallbackInfo& info);
9
12
  void initConstants(Napi::Object target);
10
13
 
11
14
  libusb_context* usb_context;
@@ -16,6 +19,7 @@ struct HotPlug {
16
19
 
17
20
  #ifdef USE_POLL
18
21
  #include <poll.h>
22
+ #include <uv.h>
19
23
  #include <sys/time.h>
20
24
 
21
25
  std::map<int, uv_poll_t*> pollByFD;
@@ -94,8 +98,11 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
94
98
 
95
99
  exports.Set("setDebugLevel", Napi::Function::New(env, SetDebugLevel));
96
100
  exports.Set("getDeviceList", Napi::Function::New(env, GetDeviceList));
101
+ exports.Set("_getLibusbCapability", Napi::Function::New(env, GetLibusbCapability));
97
102
  exports.Set("_enableHotplugEvents", Napi::Function::New(env, EnableHotplugEvents));
98
103
  exports.Set("_disableHotplugEvents", Napi::Function::New(env, DisableHotplugEvents));
104
+ exports.Set("refHotplugEvents", Napi::Function::New(env, RefHotplugEvents));
105
+ exports.Set("unrefHotplugEvents", Napi::Function::New(env, UnrefHotplugEvents));
99
106
  return exports;
100
107
  }
101
108
 
@@ -128,6 +135,17 @@ Napi::Value GetDeviceList(const Napi::CallbackInfo& info) {
128
135
  return arr;
129
136
  }
130
137
 
138
+ Napi::Value GetLibusbCapability(const Napi::CallbackInfo& info) {
139
+ Napi::Env env = info.Env();
140
+
141
+ if (info.Length() != 1 || !info[0].IsNumber()) {
142
+ THROW_BAD_ARGS("Usb::GetLibusbCapability argument is invalid!")
143
+ }
144
+
145
+ int res = libusb_has_capability(info[0].As<Napi::Number>().Int32Value());
146
+ return Napi::Number::New(env, res);
147
+ }
148
+
131
149
  Napi::ObjectReference hotplugThis;
132
150
 
133
151
  void handleHotplug(HotPlug* info){
@@ -177,6 +195,7 @@ Napi::Value EnableHotplugEvents(const Napi::CallbackInfo& info) {
177
195
 
178
196
  if (!hotplugEnabled) {
179
197
  hotplugThis.Reset(info.This().As<Napi::Object>(), 1);
198
+ hotplugThis.SuppressDestruct();
180
199
  CHECK_USB(libusb_hotplug_register_callback(usb_context,
181
200
  (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
182
201
  (libusb_hotplug_flag)0, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
@@ -198,10 +217,27 @@ Napi::Value DisableHotplugEvents(const Napi::CallbackInfo& info) {
198
217
  return env.Undefined();
199
218
  }
200
219
 
220
+ Napi::Value RefHotplugEvents(const Napi::CallbackInfo& info) {
221
+ Napi::Env env = info.Env();
222
+ Napi::HandleScope scope(env);
223
+ if (hotplugEnabled) {
224
+ hotplugQueue.ref(env);
225
+ }
226
+ return env.Undefined();
227
+ }
228
+
229
+ Napi::Value UnrefHotplugEvents(const Napi::CallbackInfo& info) {
230
+ Napi::Env env = info.Env();
231
+ Napi::HandleScope scope(env);
232
+ if (hotplugEnabled) {
233
+ hotplugQueue.unref(env);
234
+ }
235
+ return env.Undefined();
236
+ }
237
+
201
238
  #define DEFINE_CONSTANT(OBJ, VALUE) \
202
239
  OBJ.DefineProperty(Napi::PropertyDescriptor::Value(#VALUE, Napi::Number::New(OBJ.Env(), VALUE), static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)));
203
240
 
204
-
205
241
  void initConstants(Napi::Object target){
206
242
  DEFINE_CONSTANT(target, LIBUSB_CLASS_PER_INTERFACE);
207
243
  DEFINE_CONSTANT(target, LIBUSB_CLASS_AUDIO);
@@ -281,6 +317,12 @@ void initConstants(Napi::Object target){
281
317
  DEFINE_CONSTANT(target, LIBUSB_CONTROL_SETUP_SIZE);
282
318
  DEFINE_CONSTANT(target, LIBUSB_DT_BOS_SIZE);
283
319
 
320
+ // libusb_capability
321
+ DEFINE_CONSTANT(target, LIBUSB_CAP_HAS_CAPABILITY);
322
+ DEFINE_CONSTANT(target, LIBUSB_CAP_HAS_HOTPLUG);
323
+ DEFINE_CONSTANT(target, LIBUSB_CAP_HAS_HID_ACCESS);
324
+ DEFINE_CONSTANT(target, LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
325
+
284
326
  // libusb_error
285
327
  // Input/output error
286
328
  DEFINE_CONSTANT(target, LIBUSB_ERROR_IO);
package/src/node_usb.h CHANGED
@@ -10,6 +10,7 @@
10
10
  #endif
11
11
  #include <libusb.h>
12
12
 
13
+ #define NAPI_VERSION 4
13
14
  #include <napi.h>
14
15
  #include <node_buffer.h>
15
16
 
@@ -3,31 +3,39 @@
3
3
 
4
4
  template <class T>
5
5
  class UVQueue{
6
- public:
7
- typedef void (*fptr)(T);
8
-
9
- Napi::ThreadSafeFunction tsfn;
10
-
11
- UVQueue(fptr cb): callback(cb) {}
12
-
13
- void start(Napi::Env env) {
14
- Napi::Function empty_func = Napi::Function::New(env, [](const Napi::CallbackInfo& cb) {});
15
- tsfn = Napi::ThreadSafeFunction::New(env, empty_func, "libusb", 0, 1);
16
- }
17
-
18
- void stop() {
19
- tsfn.Release();
20
- }
21
-
22
- void post(T value){
23
- auto cb = callback;
24
- tsfn.BlockingCall( value, [cb](Napi::Env _env, Napi::Function _jsCallback, T val) {
25
- cb(val);
26
- });
27
- }
28
-
29
- private:
30
- fptr callback;
6
+ public:
7
+ typedef void (*fptr)(T);
8
+
9
+ Napi::ThreadSafeFunction tsfn;
10
+
11
+ UVQueue(fptr cb): callback(cb) {}
12
+
13
+ void start(Napi::Env env) {
14
+ Napi::Function empty_func = Napi::Function::New(env, [](const Napi::CallbackInfo& cb) {});
15
+ tsfn = Napi::ThreadSafeFunction::New(env, empty_func, "libusb", 0, 1);
16
+ }
17
+
18
+ void stop() {
19
+ tsfn.Release();
20
+ }
21
+
22
+ void ref(Napi::Env env) {
23
+ tsfn.Ref(env);
24
+ }
25
+
26
+ void unref(Napi::Env env) {
27
+ tsfn.Unref(env);
28
+ }
29
+
30
+ void post(T value){
31
+ auto cb = callback;
32
+ tsfn.BlockingCall( value, [cb](Napi::Env _env, Napi::Function _jsCallback, T val) {
33
+ cb(val);
34
+ });
35
+ }
36
+
37
+ private:
38
+ fptr callback;
31
39
  };
32
40
 
33
41
  #endif
package/test/usb.coffee CHANGED
@@ -1,6 +1,9 @@
1
1
  assert = require('assert')
2
2
  util = require('util')
3
- usb = require('../')
3
+ usb = require('../').usb
4
+ getDeviceList = require('../').getDeviceList
5
+ findByIds = require('../').findByIds
6
+ findBySerialNumber = require('../').findBySerialNumber
4
7
 
5
8
  if typeof gc is 'function'
6
9
  # running with --expose-gc, do a sweep between tests so valgrind blames the right one
@@ -28,18 +31,23 @@ describe 'USB Module', ->
28
31
 
29
32
  describe 'getDeviceList', ->
30
33
  it 'should return at least one device', ->
31
- l = usb.getDeviceList()
34
+ l = getDeviceList()
32
35
  assert.ok((l.length > 0))
33
36
 
34
37
  describe 'findByIds', ->
35
38
  it 'should return an array with length > 0', ->
36
- dev = usb.findByIds(0x59e3, 0x0a23)
39
+ dev = findByIds(0x59e3, 0x0a23)
40
+ assert.ok(dev, "Demo device is not attached")
41
+
42
+ describe 'findBySerialNumber', ->
43
+ it 'should return a single device ', ->
44
+ dev = findBySerialNumber('TEST_DEVICE')
37
45
  assert.ok(dev, "Demo device is not attached")
38
46
 
39
47
  describe 'Device', ->
40
48
  device = null
41
49
  before ->
42
- device = usb.findByIds(0x59e3, 0x0a23)
50
+ device = findByIds(0x59e3, 0x0a23)
43
51
 
44
52
  it 'should have sane properties', ->
45
53
  assert.ok((device.busNumber > 0), "busNumber must be larger than 0")
package/tsc/index.ts CHANGED
@@ -1,12 +1,72 @@
1
- import * as usb from './usb';
1
+ import { promisify } from 'util';
2
2
  import { WebUSB } from './webusb';
3
+ import { WebUSBDevice } from './webusb/webusb-device';
4
+ import * as usb from './usb';
5
+
6
+ /**
7
+ * Convenience method to get the first device with the specified VID and PID, or `undefined` if no such device is present.
8
+ * @param vid
9
+ * @param pid
10
+ */
11
+ const findByIds = (vid: number, pid: number): usb.Device | undefined => {
12
+ const devices = usb.getDeviceList();
13
+ return devices.find(item => item.deviceDescriptor.idVendor === vid && item.deviceDescriptor.idProduct === pid);
14
+ };
15
+
16
+ /**
17
+ * Convenience method to get the device with the specified serial number, or `undefined` if no such device is present.
18
+ * @param serialNumber
19
+ */
20
+ const findBySerialNumber = async (serialNumber: string): Promise<usb.Device | undefined> => {
21
+ const devices = usb.getDeviceList();
22
+ const opened = (device: usb.Device): boolean => !!device.interfaces;
23
+
24
+ for (const device of devices) {
25
+ try {
26
+ if (!opened(device)) {
27
+ device.open();
28
+ }
29
+
30
+ const getStringDescriptor = promisify(device.getStringDescriptor).bind(device);
31
+ const buffer = await getStringDescriptor(device.deviceDescriptor.iSerialNumber);
32
+
33
+ if (buffer && buffer.toString() === serialNumber) {
34
+ return device;
35
+ }
36
+ } catch {
37
+ // Ignore any errors, device may be a system device or inaccessible
38
+ } finally {
39
+ try {
40
+ if (opened(device)) {
41
+ device.close();
42
+ }
43
+ } catch {
44
+ // Ignore any errors, device may be a system device or inaccessible
45
+ }
46
+ }
47
+ }
48
+
49
+ return undefined;
50
+ };
51
+
52
+ const webusb = new WebUSB();
53
+ const getDeviceList = usb.getDeviceList;
54
+
55
+ export {
56
+ // Core usb object for quick access
57
+ usb,
58
+
59
+ // Convenience methods
60
+ getDeviceList,
61
+ findByIds,
62
+ findBySerialNumber,
3
63
 
4
- declare module './usb' {
5
- const webusb: WebUSB;
6
- }
64
+ // Default WebUSB object (mimics navigator.usb)
65
+ webusb,
7
66
 
8
- Object.assign(usb, {
9
- webusb: new WebUSB()
10
- });
67
+ // WebUSB class for creating custom webusb instances
68
+ WebUSB,
11
69
 
12
- export = usb;
70
+ // WebUSB Device class for turning a legacy usb.Device into a webusb device
71
+ WebUSBDevice
72
+ };
@@ -2,10 +2,11 @@
2
2
  // Eric Brody <https://github.com/underscorebrody>
3
3
  // Rob Moran <https://github.com/thegecko>
4
4
 
5
+ import { join } from 'path';
5
6
  import type { DeviceDescriptor, ConfigDescriptor, BosDescriptor } from './descriptors';
6
7
 
7
8
  /* eslint-disable @typescript-eslint/no-var-requires */
8
- const usb = require('bindings')('usb_bindings');
9
+ const usb = require('node-gyp-build')(join(__dirname, '..', '..'));
9
10
  module.exports = usb;
10
11
 
11
12
  /**
@@ -27,6 +28,17 @@ export declare function setDebugLevel(level: number): void;
27
28
 
28
29
  export declare function _enableHotplugEvents(): void;
29
30
  export declare function _disableHotplugEvents(): void;
31
+ export declare function _getLibusbCapability(capability: number): number;
32
+
33
+ /**
34
+ * Restore (re-reference) the hotplug events unreferenced by `unrefHotplugEvents()`
35
+ */
36
+ export declare function refHotplugEvents(): void;
37
+
38
+ /**
39
+ * Unreference the hotplug events from the event loop, allowing the process to exit even when listening for the `attach` and `detach` events
40
+ */
41
+ export declare function unrefHotplugEvents(): void;
30
42
 
31
43
  /** Represents a USB transfer */
32
44
  export declare class Transfer {
@@ -257,6 +269,12 @@ export declare const LIBUSB_RECIPIENT_OTHER: number;
257
269
  export declare const LIBUSB_CONTROL_SETUP_SIZE: number;
258
270
  export declare const LIBUSB_DT_BOS_SIZE: number;
259
271
 
272
+ // libusb_capability
273
+ export declare const LIBUSB_CAP_HAS_CAPABILITY: number;
274
+ export declare const LIBUSB_CAP_HAS_HOTPLUG: number;
275
+ export declare const LIBUSB_CAP_HAS_HID_ACCESS: number;
276
+ export declare const LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER: number;
277
+
260
278
  // libusb_error
261
279
  /** Input/output error */
262
280
  export declare const LIBUSB_ERROR_IO: number;
package/tsc/usb/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { promisify } from 'util';
2
1
  import { EventEmitter } from 'events';
3
2
  import { ExtendedDevice } from './device';
4
3
  import * as usb from './bindings';
@@ -22,35 +21,76 @@ interface EventListeners<T> {
22
21
  declare module './bindings' {
23
22
 
24
23
  /* eslint-disable @typescript-eslint/no-empty-interface */
25
- interface Device extends ExtendedDevice {}
26
-
27
- interface DeviceEvents extends EventListeners<DeviceEvents> {
28
- attach: Device;
29
- detach: Device;
30
- }
31
-
32
- function addListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
33
- function removeListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
34
- function on<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
35
- function off<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
36
- function once<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
37
- function listeners<K extends keyof DeviceEvents>(event: K): ((arg: DeviceEvents[K]) => void)[];
38
- function rawListeners<K extends keyof DeviceEvents>(event: K): ((arg: DeviceEvents[K]) => void)[];
39
- function removeAllListeners<K extends keyof DeviceEvents>(event?: K): void;
40
- function emit<K extends keyof DeviceEvents>(event: K, arg: DeviceEvents[K]): boolean;
41
- function listenerCount<K extends keyof DeviceEvents>(event: K): number;
42
-
43
- function findByIds(vid: number, pid: number): usb.Device | undefined;
44
- function findBySerialNumber(serialNumber: string): Promise<usb.Device | undefined>;
24
+ interface Device extends ExtendedDevice { }
25
+
26
+ interface DeviceEvents extends EventListeners<DeviceEvents> {
27
+ attach: Device;
28
+ detach: Device;
29
+ }
30
+
31
+ function addListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
32
+ function removeListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
33
+ function on<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
34
+ function off<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
35
+ function once<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
36
+ function listeners<K extends keyof DeviceEvents>(event: K): ((arg: DeviceEvents[K]) => void)[];
37
+ function rawListeners<K extends keyof DeviceEvents>(event: K): ((arg: DeviceEvents[K]) => void)[];
38
+ function removeAllListeners<K extends keyof DeviceEvents>(event?: K): void;
39
+ function emit<K extends keyof DeviceEvents>(event: K, arg: DeviceEvents[K]): boolean;
40
+ function listenerCount<K extends keyof DeviceEvents>(event: K): number;
45
41
  }
46
42
 
43
+ // Polling mechanism for discovering device changes until this is fixed:
44
+ // https://github.com/libusb/libusb/issues/86
45
+ const pollTimeout = 500;
46
+ const hotplugSupported = usb._getLibusbCapability(usb.LIBUSB_CAP_HAS_HOTPLUG) > 0;
47
+ let pollingHotplug = false;
48
+ let pollDevices: usb.Device[] = [];
49
+
50
+ const pollHotplug = (start = false) => {
51
+ if (start) {
52
+ pollingHotplug = true;
53
+ } else if (!pollingHotplug) {
54
+ return;
55
+ }
56
+
57
+ const devices = usb.getDeviceList();
58
+
59
+ if (!start) {
60
+ // Find attached devices
61
+ for (const device of devices) {
62
+ const found = pollDevices.find(item => item.deviceAddress === device.deviceAddress);
63
+ if (!found) {
64
+ usb.emit('attach', device);
65
+ }
66
+ }
67
+
68
+ // Find detached devices
69
+ for (const device of pollDevices) {
70
+ const found = devices.find(item => item.deviceAddress === device.deviceAddress);
71
+ if (!found) {
72
+ usb.emit('detach', device);
73
+ }
74
+ }
75
+ }
76
+
77
+ pollDevices = devices;
78
+ setTimeout(() => {
79
+ pollHotplug();
80
+ }, pollTimeout);
81
+ };
82
+
47
83
  usb.on('newListener', event => {
48
84
  if (event !== 'attach' && event !== 'detach') {
49
85
  return;
50
86
  }
51
87
  const listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
52
88
  if (listenerCount === 0) {
53
- usb._enableHotplugEvents();
89
+ if (hotplugSupported) {
90
+ usb._enableHotplugEvents();
91
+ } else {
92
+ pollHotplug(true);
93
+ }
54
94
  }
55
95
  });
56
96
 
@@ -60,54 +100,12 @@ usb.on('removeListener', event => {
60
100
  }
61
101
  const listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
62
102
  if (listenerCount === 0) {
63
- usb._disableHotplugEvents();
64
- }
65
- });
66
-
67
- /**
68
- * Convenience method to get the first device with the specified VID and PID, or `undefined` if no such device is present.
69
- * @param vid
70
- * @param pid
71
- */
72
- const findByIds = (vid: number, pid: number): usb.Device | undefined => {
73
- const devices = usb.getDeviceList();
74
- return devices.find(item => item.deviceDescriptor.idVendor === vid && item.deviceDescriptor.idProduct === pid);
75
- };
76
-
77
- /**
78
- * Convenience method to get the device with the specified serial number, or `undefined` if no such device is present.
79
- * @param serialNumber
80
- */
81
- const findBySerialNumber = async (serialNumber: string): Promise<usb.Device | undefined> => {
82
- const devices = usb.getDeviceList();
83
-
84
- for (const device of devices) {
85
- try {
86
- device.open();
87
-
88
- const getStringDescriptor = promisify(device.getStringDescriptor).bind(device);
89
- const buffer = await getStringDescriptor(device.deviceDescriptor.iSerialNumber);
90
-
91
- if (buffer && buffer.toString() === serialNumber) {
92
- return device;
93
- }
94
- } catch {
95
- // Ignore any errors, device may be a system device or inaccessible
96
- } finally {
97
- try {
98
- device.close();
99
- } catch {
100
- // Ignore any errors, device may be a system device or inaccessible
101
- }
103
+ if (hotplugSupported) {
104
+ usb._disableHotplugEvents();
105
+ } else {
106
+ pollingHotplug = false;
102
107
  }
103
108
  }
104
-
105
- return undefined;
106
- };
107
-
108
- Object.assign(usb, {
109
- findByIds,
110
- findBySerialNumber
111
109
  });
112
110
 
113
111
  export = usb;
@@ -28,7 +28,7 @@ export class Interface {
28
28
  this.interfaceNumber = this.descriptor.bInterfaceNumber;
29
29
  this.endpoints = [];
30
30
  const len = this.descriptor.endpoints.length;
31
- for (let i=0; i<len; i++){
31
+ for (let i = 0; i < len; i++) {
32
32
  const desc = this.descriptor.endpoints[i];
33
33
  const c = (desc.bEndpointAddress & LIBUSB_ENDPOINT_IN) ? InEndpoint : OutEndpoint;
34
34
  this.endpoints[i] = new c(this.device, desc);
@@ -145,7 +145,7 @@ export class Interface {
145
145
  */
146
146
  public setAltSetting(altSetting: number, callback?: (error: LibUSBException | undefined) => void): void {
147
147
  this.device.__setInterface(this.id, altSetting, error => {
148
- if (!error){
148
+ if (!error) {
149
149
  this.altSetting = altSetting;
150
150
  this.refresh();
151
151
  }