usb 2.0.0-alpha.2 → 2.1.0

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 (258) hide show
  1. package/.gitmodules +1 -1
  2. package/CHANGELOG.md +100 -0
  3. package/README.md +573 -0
  4. package/binding.gyp +12 -2
  5. package/dist/index.d.ts +4 -4
  6. package/dist/index.js +14 -8
  7. package/dist/index.js.map +1 -1
  8. package/dist/usb/bindings.d.ts +13 -0
  9. package/dist/usb/bindings.js +2 -1
  10. package/dist/usb/bindings.js.map +1 -1
  11. package/dist/usb/index.js +86 -2
  12. package/dist/usb/index.js.map +1 -1
  13. package/dist/usb/interface.js.map +1 -1
  14. package/dist/webusb/index.d.ts +32 -19
  15. package/dist/webusb/index.js +163 -67
  16. package/dist/webusb/index.js.map +1 -1
  17. package/dist/webusb/webusb-device.d.ts +1 -1
  18. package/dist/webusb/webusb-device.js +27 -15
  19. package/dist/webusb/webusb-device.js.map +1 -1
  20. package/libusb/.private/pre-commit.sh +7 -1
  21. package/libusb/.travis.yml +49 -0
  22. package/libusb/AUTHORS +44 -3
  23. package/libusb/Brewfile +4 -0
  24. package/libusb/ChangeLog +74 -2
  25. package/libusb/README.md +32 -0
  26. package/libusb/TODO +1 -1
  27. package/libusb/Xcode/common.xcconfig +12 -0
  28. package/libusb/Xcode/config.h +25 -0
  29. package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +959 -1
  30. package/libusb/android/README +4 -2
  31. package/libusb/android/config.h +75 -0
  32. package/libusb/appveyor.yml +41 -0
  33. package/libusb/appveyor_cygwin.bat +11 -0
  34. package/libusb/appveyor_minGW.bat +19 -0
  35. package/libusb/autogen.sh +1 -1
  36. package/libusb/bootstrap.sh +3 -16
  37. package/libusb/configure.ac +108 -80
  38. package/libusb/doc/doxygen.cfg.in +1785 -739
  39. package/libusb/examples/Makefile.am +1 -1
  40. package/libusb/examples/dpfp.c +3 -1
  41. package/libusb/examples/dpfp_threaded.c +23 -10
  42. package/libusb/examples/ezusb.c +3 -3
  43. package/libusb/examples/ezusb.h +2 -2
  44. package/libusb/examples/fxload.c +31 -9
  45. package/libusb/examples/hotplugtest.c +35 -7
  46. package/libusb/examples/listdevs.c +3 -1
  47. package/libusb/examples/sam3u_benchmark.c +3 -3
  48. package/libusb/examples/testlibusb.c +277 -0
  49. package/libusb/examples/xusb.c +40 -34
  50. package/libusb/libusb/Makefile.am +49 -23
  51. package/libusb/libusb/core.c +855 -457
  52. package/libusb/libusb/descriptor.c +72 -78
  53. package/libusb/libusb/hotplug.c +122 -76
  54. package/libusb/libusb/hotplug.h +42 -25
  55. package/libusb/libusb/io.c +625 -390
  56. package/libusb/libusb/libusb-1.0.def +12 -0
  57. package/libusb/libusb/libusb.h +218 -150
  58. package/libusb/libusb/libusbi.h +346 -176
  59. package/libusb/libusb/os/darwin_usb.c +604 -319
  60. package/libusb/libusb/os/darwin_usb.h +61 -20
  61. package/libusb/libusb/os/haiku_pollfs.cpp +367 -0
  62. package/libusb/libusb/os/haiku_usb.h +113 -0
  63. package/libusb/libusb/os/haiku_usb_backend.cpp +533 -0
  64. package/libusb/libusb/os/haiku_usb_raw.cpp +267 -0
  65. package/libusb/libusb/os/haiku_usb_raw.h +188 -0
  66. package/libusb/libusb/os/linux_netlink.c +186 -146
  67. package/libusb/libusb/os/linux_udev.c +36 -14
  68. package/libusb/libusb/os/linux_usbfs.c +426 -225
  69. package/libusb/libusb/os/linux_usbfs.h +5 -3
  70. package/libusb/libusb/os/netbsd_usb.c +21 -77
  71. package/libusb/libusb/os/openbsd_usb.c +32 -115
  72. package/libusb/libusb/os/poll_posix.c +38 -5
  73. package/libusb/libusb/os/poll_posix.h +3 -0
  74. package/libusb/libusb/os/poll_windows.c +277 -626
  75. package/libusb/libusb/os/poll_windows.h +11 -44
  76. package/libusb/libusb/os/sunos_usb.c +1695 -0
  77. package/libusb/libusb/os/sunos_usb.h +80 -0
  78. package/libusb/libusb/os/threads_posix.c +24 -26
  79. package/libusb/libusb/os/threads_posix.h +73 -21
  80. package/libusb/libusb/os/threads_windows.c +71 -157
  81. package/libusb/libusb/os/threads_windows.h +68 -44
  82. package/libusb/libusb/os/wince_usb.c +276 -420
  83. package/libusb/libusb/os/wince_usb.h +23 -28
  84. package/libusb/libusb/os/windows_common.h +78 -58
  85. package/libusb/libusb/os/windows_nt_common.c +1010 -0
  86. package/libusb/libusb/os/windows_nt_common.h +110 -0
  87. package/libusb/libusb/os/windows_nt_shared_types.h +147 -0
  88. package/libusb/libusb/os/windows_usbdk.c +830 -0
  89. package/libusb/libusb/os/windows_usbdk.h +103 -0
  90. package/libusb/libusb/os/windows_winusb.c +4391 -0
  91. package/libusb/libusb/os/windows_winusb.h +783 -0
  92. package/libusb/libusb/strerror.c +41 -7
  93. package/libusb/libusb/sync.c +41 -13
  94. package/libusb/libusb/version.h +1 -1
  95. package/libusb/libusb/version_nano.h +1 -1
  96. package/libusb/libusb-1.0.pc.in +1 -1
  97. package/libusb/msvc/appveyor.bat +27 -0
  98. package/libusb/msvc/config.h +5 -4
  99. package/libusb/msvc/ddk_build.cmd +87 -43
  100. package/libusb/msvc/fxload_2010.vcxproj +24 -104
  101. package/libusb/msvc/fxload_2012.vcxproj +24 -107
  102. package/libusb/msvc/fxload_2013.vcxproj +24 -107
  103. package/libusb/msvc/fxload_2015.vcxproj +91 -0
  104. package/libusb/msvc/fxload_2017.vcxproj +114 -0
  105. package/libusb/msvc/fxload_sources +1 -1
  106. package/libusb/msvc/getopt_2010.vcxproj +16 -75
  107. package/libusb/msvc/getopt_2012.vcxproj +16 -79
  108. package/libusb/msvc/getopt_2013.vcxproj +16 -79
  109. package/libusb/msvc/getopt_2015.vcxproj +73 -0
  110. package/libusb/msvc/getopt_2017.vcxproj +98 -0
  111. package/libusb/msvc/getopt_sources +6 -2
  112. package/libusb/msvc/hotplugtest_2010.vcxproj +18 -99
  113. package/libusb/msvc/hotplugtest_2012.vcxproj +18 -102
  114. package/libusb/msvc/hotplugtest_2013.vcxproj +18 -102
  115. package/libusb/msvc/hotplugtest_2015.vcxproj +83 -0
  116. package/libusb/msvc/hotplugtest_2017.vcxproj +106 -0
  117. package/libusb/msvc/hotplugtest_sources +1 -1
  118. package/libusb/msvc/libusb_2005.sln +20 -20
  119. package/libusb/msvc/libusb_2010.sln +57 -46
  120. package/libusb/msvc/libusb_2012.sln +57 -46
  121. package/libusb/msvc/libusb_2013.sln +57 -50
  122. package/libusb/msvc/libusb_2015.sln +59 -52
  123. package/libusb/msvc/libusb_2017.sln +186 -0
  124. package/libusb/msvc/libusb_dll.dsp +2 -2
  125. package/libusb/msvc/libusb_dll_2005.vcproj +30 -2
  126. package/libusb/msvc/libusb_dll_2010.vcxproj +26 -90
  127. package/libusb/msvc/libusb_dll_2012.vcxproj +28 -96
  128. package/libusb/msvc/libusb_dll_2013.vcxproj +28 -96
  129. package/libusb/msvc/libusb_dll_2015.vcxproj +107 -0
  130. package/libusb/msvc/libusb_dll_2017.vcxproj +134 -0
  131. package/libusb/msvc/libusb_dll_wince.vcproj +9 -1
  132. package/libusb/msvc/libusb_sources +10 -5
  133. package/libusb/msvc/libusb_static.dsp +2 -2
  134. package/libusb/msvc/libusb_static_2005.vcproj +32 -4
  135. package/libusb/msvc/libusb_static_2010.vcxproj +24 -83
  136. package/libusb/msvc/libusb_static_2012.vcxproj +25 -87
  137. package/libusb/msvc/libusb_static_2013.vcxproj +25 -87
  138. package/libusb/msvc/libusb_static_2015.vcxproj +98 -0
  139. package/libusb/msvc/libusb_static_2017.vcxproj +117 -0
  140. package/libusb/msvc/libusb_static_wince.vcproj +20 -26
  141. package/libusb/msvc/libusb_wince.sln +88 -88
  142. package/libusb/msvc/listdevs_2010.vcxproj +16 -99
  143. package/libusb/msvc/listdevs_2012.vcxproj +16 -102
  144. package/libusb/msvc/listdevs_2013.vcxproj +16 -102
  145. package/libusb/msvc/listdevs_2015.vcxproj +83 -0
  146. package/libusb/msvc/listdevs_2017.vcxproj +106 -0
  147. package/libusb/msvc/listdevs_sources +2 -1
  148. package/libusb/msvc/stress_2010.vcxproj +20 -101
  149. package/libusb/msvc/stress_2012.vcxproj +20 -104
  150. package/libusb/msvc/stress_2013.vcxproj +20 -104
  151. package/libusb/msvc/stress_2015.vcxproj +87 -0
  152. package/libusb/msvc/stress_2017.vcxproj +110 -0
  153. package/libusb/msvc/stress_sources +21 -0
  154. package/libusb/msvc/testlibusb_2010.vcxproj +82 -0
  155. package/libusb/msvc/testlibusb_2012.vcxproj +83 -0
  156. package/libusb/msvc/testlibusb_2013.vcxproj +83 -0
  157. package/libusb/msvc/testlibusb_2015.vcxproj +83 -0
  158. package/libusb/msvc/testlibusb_2017.vcxproj +106 -0
  159. package/libusb/msvc/testlibusb_sources +20 -0
  160. package/libusb/msvc/xusb_2010.vcxproj +17 -98
  161. package/libusb/msvc/xusb_2012.vcxproj +17 -101
  162. package/libusb/msvc/xusb_2013.vcxproj +17 -101
  163. package/libusb/msvc/xusb_2015.vcxproj +83 -0
  164. package/libusb/msvc/xusb_2017.vcxproj +106 -0
  165. package/libusb/msvc/xusb_sources +1 -1
  166. package/libusb/tests/stress.c +2 -2
  167. package/libusb/tests/testlib.c +0 -4
  168. package/libusb/travis-autogen.sh +39 -0
  169. package/libusb.gypi +21 -2
  170. package/package.json +18 -13
  171. package/prebuilds/android-arm/node.napi.node +0 -0
  172. package/prebuilds/android-arm64/node.napi.node +0 -0
  173. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  174. package/prebuilds/linux-arm/node.napi.node +0 -0
  175. package/prebuilds/linux-arm64/node.napi.node +0 -0
  176. package/prebuilds/linux-ia32/node.napi.node +0 -0
  177. package/prebuilds/linux-x64/node.napi.node +0 -0
  178. package/prebuilds/win32-ia32/node.napi.node +0 -0
  179. package/prebuilds/win32-x64/node.napi.node +0 -0
  180. package/src/device.cc +7 -7
  181. package/src/node_usb.cc +43 -1
  182. package/src/node_usb.h +1 -0
  183. package/src/uv_async_queue.h +33 -25
  184. package/test/usb.coffee +6 -0
  185. package/tsc/index.ts +13 -7
  186. package/tsc/usb/bindings.ts +19 -1
  187. package/tsc/usb/index.ts +67 -19
  188. package/tsc/usb/interface.ts +2 -2
  189. package/tsc/webusb/index.ts +197 -74
  190. package/tsc/webusb/webusb-device.ts +30 -17
  191. package/.github/workflows/prebuild.yml +0 -48
  192. package/Readme.md +0 -339
  193. package/dist/webusb/typed-event-target.d.ts +0 -11
  194. package/dist/webusb/typed-event-target.js +0 -21
  195. package/dist/webusb/typed-event-target.js.map +0 -1
  196. package/docs/assets/css/main.css +0 -2660
  197. package/docs/assets/images/icons.png +0 -0
  198. package/docs/assets/images/icons@2x.png +0 -0
  199. package/docs/assets/images/widgets.png +0 -0
  200. package/docs/assets/images/widgets@2x.png +0 -0
  201. package/docs/assets/js/main.js +0 -248
  202. package/docs/assets/js/search.js +0 -1
  203. package/docs/classes/usb_bindings.device.html +0 -1338
  204. package/docs/classes/usb_bindings.libusbexception.html +0 -234
  205. package/docs/classes/usb_bindings.transfer.html +0 -344
  206. package/docs/classes/usb_capability.capability.html +0 -297
  207. package/docs/classes/usb_device.extendeddevice.html +0 -766
  208. package/docs/classes/usb_endpoint.endpoint.html +0 -472
  209. package/docs/classes/usb_endpoint.inendpoint.html +0 -766
  210. package/docs/classes/usb_endpoint.outendpoint.html +0 -582
  211. package/docs/classes/usb_interface.interface.html +0 -648
  212. package/docs/classes/webusb.webusb-1.html +0 -615
  213. package/docs/classes/webusb_mutex.mutex.html +0 -270
  214. package/docs/classes/webusb_typed_event_target.typedeventtarget.html +0 -443
  215. package/docs/classes/webusb_webusb_device.webusbdevice.html +0 -904
  216. package/docs/index.html +0 -500
  217. package/docs/interfaces/usb.deviceevents.html +0 -242
  218. package/docs/interfaces/usb_descriptors.bosdescriptor.html +0 -293
  219. package/docs/interfaces/usb_descriptors.capabilitydescriptor.html +0 -274
  220. package/docs/interfaces/usb_descriptors.configdescriptor.html +0 -388
  221. package/docs/interfaces/usb_descriptors.devicedescriptor.html +0 -464
  222. package/docs/interfaces/usb_descriptors.endpointdescriptor.html +0 -370
  223. package/docs/interfaces/usb_descriptors.interfacedescriptor.html +0 -407
  224. package/docs/interfaces/webusb.usboptions.html +0 -226
  225. package/docs/modules/index.html +0 -304
  226. package/docs/modules/usb.html +0 -173
  227. package/docs/modules/usb_bindings.html +0 -2248
  228. package/docs/modules/usb_capability.html +0 -156
  229. package/docs/modules/usb_descriptors.html +0 -176
  230. package/docs/modules/usb_device.html +0 -156
  231. package/docs/modules/usb_endpoint.html +0 -164
  232. package/docs/modules/usb_interface.html +0 -156
  233. package/docs/modules/webusb.html +0 -165
  234. package/docs/modules/webusb_mutex.html +0 -156
  235. package/docs/modules/webusb_typed_event_target.html +0 -156
  236. package/docs/modules/webusb_webusb_device.html +0 -156
  237. package/docs/modules.html +0 -156
  238. package/libusb/INSTALL +0 -234
  239. package/libusb/README +0 -28
  240. package/libusb/libusb/os/windows_usb.c +0 -5347
  241. package/libusb/libusb/os/windows_usb.h +0 -971
  242. package/libusb/msvc/fxload_2010.vcxproj.filters +0 -25
  243. package/libusb/msvc/fxload_2012.vcxproj.filters +0 -25
  244. package/libusb/msvc/getopt_2010.vcxproj.filters +0 -26
  245. package/libusb/msvc/getopt_2012.vcxproj.filters +0 -26
  246. package/libusb/msvc/hotplugtest_2010.vcxproj.filters +0 -14
  247. package/libusb/msvc/hotplugtest_2012.vcxproj.filters +0 -14
  248. package/libusb/msvc/libusb_dll_2010.vcxproj.filters +0 -81
  249. package/libusb/msvc/libusb_dll_2012.vcxproj.filters +0 -84
  250. package/libusb/msvc/libusb_static_2010.vcxproj.filters +0 -74
  251. package/libusb/msvc/libusb_static_2012.vcxproj.filters +0 -74
  252. package/libusb/msvc/listdevs_2010.vcxproj.filters +0 -14
  253. package/libusb/msvc/listdevs_2012.vcxproj.filters +0 -14
  254. package/libusb/msvc/stress_2010.vcxproj.filters +0 -25
  255. package/libusb/msvc/stress_2012.vcxproj.filters +0 -25
  256. package/libusb/msvc/xusb_2010.vcxproj.filters +0 -14
  257. package/libusb/msvc/xusb_2012.vcxproj.filters +0 -14
  258. 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.2",
5
+ "version": "2.1.0",
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,24 @@
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-cross": "prebuildify-cross --napi --target 10.16.0 --strip",
51
+ "prepublishOnly": "prebuildify-ci download",
52
+ "prebuild-download": "prebuildify-ci download"
50
53
  },
51
54
  "dependencies": {
52
55
  "@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"
56
+ "node-addon-api": "^4.2.0",
57
+ "node-gyp-build": "^4.3.0"
56
58
  },
57
59
  "devDependencies": {
58
60
  "@types/node": "^14.14.41",
@@ -60,9 +62,12 @@
60
62
  "@typescript-eslint/parser": "^4.28.0",
61
63
  "coffeescript": "^2.5.1",
62
64
  "eslint": "^7.29.0",
63
- "mocha": "^8.3.2",
64
- "prebuild": "^10.0.1",
65
- "typedoc": "^0.20.36",
65
+ "mocha": "^9.1.3",
66
+ "node-gyp": "^7.1.2",
67
+ "prebuildify": "^4.2.1",
68
+ "prebuildify-ci": "^1.0.5",
69
+ "prebuildify-cross": "^4.0.1",
70
+ "typedoc": "^0.22.10",
66
71
  "typescript": "~4.2.4"
67
72
  },
68
73
  "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
@@ -3,6 +3,7 @@ util = require('util')
3
3
  usb = require('../').usb
4
4
  getDeviceList = require('../').getDeviceList
5
5
  findByIds = require('../').findByIds
6
+ findBySerialNumber = require('../').findBySerialNumber
6
7
 
7
8
  if typeof gc is 'function'
8
9
  # running with --expose-gc, do a sweep between tests so valgrind blames the right one
@@ -38,6 +39,11 @@ describe 'findByIds', ->
38
39
  dev = findByIds(0x59e3, 0x0a23)
39
40
  assert.ok(dev, "Demo device is not attached")
40
41
 
42
+ describe 'findBySerialNumber', ->
43
+ it 'should return a single device ', ->
44
+ dev = findBySerialNumber('TEST_DEVICE')
45
+ assert.ok(dev, "Demo device is not attached")
46
+
41
47
  describe 'Device', ->
42
48
  device = null
43
49
  before ->
package/tsc/index.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import { promisify } from 'util';
2
- import { WebUSB } from './webusb';
2
+ import { WebUSB, getWebUsb } from './webusb';
3
3
  import { WebUSBDevice } from './webusb/webusb-device';
4
4
  import * as usb from './usb';
5
5
 
6
+ const webusb = new WebUSB();
7
+ const getDeviceList = usb.getDeviceList;
8
+
6
9
  /**
7
10
  * Convenience method to get the first device with the specified VID and PID, or `undefined` if no such device is present.
8
11
  * @param vid
@@ -19,10 +22,13 @@ const findByIds = (vid: number, pid: number): usb.Device | undefined => {
19
22
  */
20
23
  const findBySerialNumber = async (serialNumber: string): Promise<usb.Device | undefined> => {
21
24
  const devices = usb.getDeviceList();
25
+ const opened = (device: usb.Device): boolean => !!device.interfaces;
22
26
 
23
27
  for (const device of devices) {
24
28
  try {
25
- device.open();
29
+ if (!opened(device)) {
30
+ device.open();
31
+ }
26
32
 
27
33
  const getStringDescriptor = promisify(device.getStringDescriptor).bind(device);
28
34
  const buffer = await getStringDescriptor(device.deviceDescriptor.iSerialNumber);
@@ -34,7 +40,9 @@ const findBySerialNumber = async (serialNumber: string): Promise<usb.Device | un
34
40
  // Ignore any errors, device may be a system device or inaccessible
35
41
  } finally {
36
42
  try {
37
- device.close();
43
+ if (opened(device)) {
44
+ device.close();
45
+ }
38
46
  } catch {
39
47
  // Ignore any errors, device may be a system device or inaccessible
40
48
  }
@@ -44,9 +52,6 @@ const findBySerialNumber = async (serialNumber: string): Promise<usb.Device | un
44
52
  return undefined;
45
53
  };
46
54
 
47
- const webusb = new WebUSB();
48
- const getDeviceList = usb.getDeviceList;
49
-
50
55
  export {
51
56
  // Core usb object for quick access
52
57
  usb,
@@ -55,6 +60,7 @@ export {
55
60
  getDeviceList,
56
61
  findByIds,
57
62
  findBySerialNumber,
63
+ getWebUsb,
58
64
 
59
65
  // Default WebUSB object (mimics navigator.usb)
60
66
  webusb,
@@ -62,6 +68,6 @@ export {
62
68
  // WebUSB class for creating custom webusb instances
63
69
  WebUSB,
64
70
 
65
- // WebUSB Device class for turning a core usb.Device into a webusb device
71
+ // WebUSB Device class for turning a legacy usb.Device into a webusb device
66
72
  WebUSBDevice
67
73
  };
@@ -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
@@ -21,32 +21,76 @@ interface EventListeners<T> {
21
21
  declare module './bindings' {
22
22
 
23
23
  /* eslint-disable @typescript-eslint/no-empty-interface */
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;
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;
41
41
  }
42
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
+
43
83
  usb.on('newListener', event => {
44
84
  if (event !== 'attach' && event !== 'detach') {
45
85
  return;
46
86
  }
47
87
  const listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
48
88
  if (listenerCount === 0) {
49
- usb._enableHotplugEvents();
89
+ if (hotplugSupported) {
90
+ usb._enableHotplugEvents();
91
+ } else {
92
+ pollHotplug(true);
93
+ }
50
94
  }
51
95
  });
52
96
 
@@ -56,7 +100,11 @@ usb.on('removeListener', event => {
56
100
  }
57
101
  const listenerCount = usb.listenerCount('attach') + usb.listenerCount('detach');
58
102
  if (listenerCount === 0) {
59
- usb._disableHotplugEvents();
103
+ if (hotplugSupported) {
104
+ usb._disableHotplugEvents();
105
+ } else {
106
+ pollingHotplug = false;
107
+ }
60
108
  }
61
109
  });
62
110
 
@@ -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
  }