usb 2.4.3 → 2.5.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.
@@ -3,187 +3,187 @@ util = require('util')
3
3
  webusb = require('../').webusb
4
4
 
5
5
  if typeof gc is 'function'
6
- # running with --expose-gc, do a sweep between tests so valgrind blames the right one
7
- afterEach -> gc()
6
+ # running with --expose-gc, do a sweep between tests so valgrind blames the right one
7
+ afterEach -> gc()
8
8
 
9
9
  describe 'WebUSB Module', ->
10
- it 'should describe basic constants', ->
11
- assert.notEqual(webusb, undefined, "webusb must be undefined")
10
+ it 'should describe basic constants', ->
11
+ assert.notEqual(webusb, undefined, "webusb must be undefined")
12
12
 
13
13
  describe 'requestDevice', ->
14
- it 'should return a device', ->
15
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
16
- assert.notEqual(device, undefined)
14
+ it 'should return a device', ->
15
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
16
+ assert.notEqual(device, undefined)
17
17
 
18
18
  describe 'getDevices', ->
19
- it 'should return one device', ->
20
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
21
- l = await webusb.getDevices()
22
- assert.equal(l.length, 1)
23
- assert.notEqual(l[0], undefined)
24
- assert.deepEqual(l[0], device)
19
+ it 'should return one device', ->
20
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
21
+ l = await webusb.getDevices()
22
+ assert.equal(l.length, 1)
23
+ assert.notEqual(l[0], undefined)
24
+ assert.deepEqual(l[0], device)
25
25
 
26
26
  describe 'Device properties', ->
27
- device = null
28
- before ->
29
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
27
+ device = null
28
+ before ->
29
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
30
30
 
31
- it 'should have usb version properties', ->
32
- assert.equal(device.usbVersionMajor, 1)
33
- assert.equal(device.usbVersionMinor, 1)
34
- assert.equal(device.usbVersionSubminor, 0)
31
+ it 'should have usb version properties', ->
32
+ assert.equal(device.usbVersionMajor, 1)
33
+ assert.equal(device.usbVersionMinor, 1)
34
+ assert.equal(device.usbVersionSubminor, 0)
35
35
 
36
- it 'should have device version properties', ->
37
- assert.equal(device.deviceVersionMajor, 1)
38
- assert.equal(device.deviceVersionMinor, 1)
39
- assert.equal(device.deviceVersionSubminor, 0)
36
+ it 'should have device version properties', ->
37
+ assert.equal(device.deviceVersionMajor, 1)
38
+ assert.equal(device.deviceVersionMinor, 1)
39
+ assert.equal(device.deviceVersionSubminor, 0)
40
40
 
41
- it 'should have class properties', ->
42
- assert.equal(device.deviceClass, 0)
43
- assert.equal(device.deviceSubclass, 0)
41
+ it 'should have class properties', ->
42
+ assert.equal(device.deviceClass, 0)
43
+ assert.equal(device.deviceSubclass, 0)
44
44
 
45
- it 'should have protocol property', ->
46
- assert.equal(device.deviceProtocol, 0)
45
+ it 'should have protocol property', ->
46
+ assert.equal(device.deviceProtocol, 0)
47
47
 
48
- it 'should have vid/pid properties', ->
49
- assert.equal(device.vendorId, 0x59e3)
50
- assert.equal(device.productId, 0x0a23)
48
+ it 'should have vid/pid properties', ->
49
+ assert.equal(device.vendorId, 0x59e3)
50
+ assert.equal(device.productId, 0x0a23)
51
51
 
52
- it 'should have a single configuration', ->
53
- assert.equal(device.configurations.length, 1)
54
- assert.equal(device.configurations[0].configurationValue, 1)
52
+ it 'should have a single configuration', ->
53
+ assert.equal(device.configurations.length, 1)
54
+ assert.equal(device.configurations[0].configurationValue, 1)
55
55
 
56
- it 'should have a configuration property', ->
57
- assert.notEqual(device.configuration, undefined)
56
+ it 'should have a configuration property', ->
57
+ assert.notEqual(device.configuration, undefined)
58
58
 
59
- it 'should have a single interface', ->
60
- assert.equal(device.configuration.interfaces.length, 1)
61
- assert.equal(device.configuration.interfaces[0].interfaceNumber, 0)
59
+ it 'should have a single interface', ->
60
+ assert.equal(device.configuration.interfaces.length, 1)
61
+ assert.equal(device.configuration.interfaces[0].interfaceNumber, 0)
62
62
 
63
- it 'should have a single alternate', ->
64
- assert.equal(device.configuration.interfaces[0].alternates.length, 1)
65
- assert.equal(device.configuration.interfaces[0].alternates[0].alternateSetting, 0)
63
+ it 'should have a single alternate', ->
64
+ assert.equal(device.configuration.interfaces[0].alternates.length, 1)
65
+ assert.equal(device.configuration.interfaces[0].alternates[0].alternateSetting, 0)
66
66
 
67
67
  describe 'String descriptors', ->
68
- device = null
69
- before ->
70
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
68
+ device = null
69
+ before ->
70
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
71
71
 
72
- it 'gets serialNumber string', ->
73
- assert.equal(device.serialNumber, "TEST_DEVICE")
72
+ it 'gets serialNumber string', ->
73
+ assert.equal(device.serialNumber, "TEST_DEVICE")
74
74
 
75
- it 'gets manufacturerName string', ->
76
- assert.equal(device.manufacturerName, "Nonolith Labs")
75
+ it 'gets manufacturerName string', ->
76
+ assert.equal(device.manufacturerName, "Nonolith Labs")
77
77
 
78
- it 'gets productName string', ->
79
- assert.equal(device.productName, "STM32F103 Test Device")
78
+ it 'gets productName string', ->
79
+ assert.equal(device.productName, "STM32F103 Test Device")
80
80
 
81
81
  describe 'Device access', ->
82
- device = null
83
- before ->
84
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
82
+ device = null
83
+ before ->
84
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
85
85
 
86
- it 'is not open', ->
87
- assert.equal(device.opened, false)
86
+ it 'is not open', ->
87
+ assert.equal(device.opened, false)
88
88
 
89
- it 'is opens and closes', ->
90
- assert.equal(device.opened, false)
91
- await device.open()
92
- assert.equal(device.opened, true)
93
- await device.close()
94
- assert.equal(device.opened, false)
89
+ it 'is opens and closes', ->
90
+ assert.equal(device.opened, false)
91
+ await device.open()
92
+ assert.equal(device.opened, true)
93
+ await device.close()
94
+ assert.equal(device.opened, false)
95
95
 
96
96
  describe 'Configurations', ->
97
- device = null
98
- before ->
99
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
100
- await device.open()
97
+ device = null
98
+ before ->
99
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
100
+ await device.open()
101
101
 
102
- it 'selects existing configuration', ->
103
- assert.doesNotReject(device.selectConfiguration(1))
102
+ it 'selects existing configuration', ->
103
+ assert.doesNotReject(device.selectConfiguration(1))
104
104
 
105
- it 'fails to select missing configuration', ->
106
- assert.rejects(device.selectConfiguration(99))
105
+ it 'fails to select missing configuration', ->
106
+ assert.rejects(device.selectConfiguration(99))
107
107
 
108
- after ->
109
- device.close()
108
+ after ->
109
+ device.close()
110
110
 
111
111
  describe 'Interfaces', ->
112
- device = null
113
- before ->
114
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
115
- await device.open()
112
+ device = null
113
+ before ->
114
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
115
+ await device.open()
116
116
 
117
- it 'claims existing interface', ->
118
- assert.doesNotReject(device.claimInterface(0))
117
+ it 'claims existing interface', ->
118
+ assert.doesNotReject(device.claimInterface(0))
119
119
 
120
- it 'fails to claim missing interface', ->
121
- assert.rejects(device.claimInterface(99))
120
+ it 'fails to claim missing interface', ->
121
+ assert.rejects(device.claimInterface(99))
122
122
 
123
- it 'releases existing interface', ->
124
- assert.doesNotReject(device.releaseInterface(0))
123
+ it 'releases existing interface', ->
124
+ assert.doesNotReject(device.releaseInterface(0))
125
125
 
126
- it 'fails to release missing interface', ->
127
- assert.rejects(device.releaseInterface(99))
126
+ it 'fails to release missing interface', ->
127
+ assert.rejects(device.releaseInterface(99))
128
128
 
129
- after ->
130
- device.close()
129
+ after ->
130
+ device.close()
131
131
 
132
132
  describe 'Alternates', ->
133
- device = null
134
- before ->
135
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
136
- await device.open()
137
- await device.claimInterface(0)
133
+ device = null
134
+ before ->
135
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
136
+ await device.open()
137
+ await device.claimInterface(0)
138
138
 
139
- it 'selects existing alternate', ->
140
- assert.doesNotReject(device.selectAlternateInterface(0, 0))
139
+ it 'selects existing alternate', ->
140
+ assert.doesNotReject(device.selectAlternateInterface(0, 0))
141
141
 
142
- after ->
143
- device.close()
142
+ after ->
143
+ device.close()
144
144
 
145
145
  describe 'Transfers', ->
146
- device = null
147
- b = Uint8Array.from([0x30...0x40]).buffer
148
-
149
- before ->
150
- device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
151
- await device.open()
152
- await device.claimInterface(0)
153
-
154
- it 'should control transfer OUT', ->
155
- transferResult = await device.controlTransferOut({
156
- requestType: 'device',
157
- recipient: 'vendor';
158
- request: 0x81,
159
- value: 0,
160
- index: 0
161
- }, b)
162
-
163
- assert.equal(transferResult.status, 'ok')
164
- assert.equal(transferResult.bytesWritten, b.byteLength)
165
-
166
- it 'should control transfer IN', ->
167
- transferResult = await device.controlTransferIn({
168
- requestType: 'device',
169
- recipient: 'vendor';
170
- request: 0x81,
171
- value: 0,
172
- index: 0
173
- }, 128)
174
-
175
- assert.equal(transferResult.status, 'ok')
176
- assert.equal(transferResult.data.buffer.toString(), b.toString())
177
-
178
- it 'should transfer OUT', ->
179
- transferResult = await device.transferOut(2, b)
180
- assert.equal(transferResult.status, 'ok')
181
- assert.equal(transferResult.bytesWritten, b.byteLength)
182
-
183
- it 'should transfer IN', ->
184
- transferResult = await device.transferIn(1, 64)
185
- assert.equal(transferResult.status, 'ok')
186
- assert.equal(transferResult.data.byteLength, 64)
187
-
188
- after ->
189
- device.close()
146
+ device = null
147
+ b = Uint8Array.from([0x30...0x40]).buffer
148
+
149
+ before ->
150
+ device = await webusb.requestDevice({ filters: [{ vendorId: 0x59e3 }] });
151
+ await device.open()
152
+ await device.claimInterface(0)
153
+
154
+ it 'should control transfer OUT', ->
155
+ transferResult = await device.controlTransferOut({
156
+ requestType: 'device',
157
+ recipient: 'vendor';
158
+ request: 0x81,
159
+ value: 0,
160
+ index: 0
161
+ }, b)
162
+
163
+ assert.equal(transferResult.status, 'ok')
164
+ assert.equal(transferResult.bytesWritten, b.byteLength)
165
+
166
+ it 'should control transfer IN', ->
167
+ transferResult = await device.controlTransferIn({
168
+ requestType: 'device',
169
+ recipient: 'vendor';
170
+ request: 0x81,
171
+ value: 0,
172
+ index: 0
173
+ }, 128)
174
+
175
+ assert.equal(transferResult.status, 'ok')
176
+ assert.equal(transferResult.data.buffer.toString(), b.toString())
177
+
178
+ it 'should transfer OUT', ->
179
+ transferResult = await device.transferOut(2, b)
180
+ assert.equal(transferResult.status, 'ok')
181
+ assert.equal(transferResult.bytesWritten, b.byteLength)
182
+
183
+ it 'should transfer IN', ->
184
+ transferResult = await device.transferIn(1, 64)
185
+ assert.equal(transferResult.status, 'ok')
186
+ assert.equal(transferResult.data.byteLength, 64)
187
+
188
+ after ->
189
+ device.close()
@@ -31,6 +31,7 @@ export declare function setDebugLevel(level: number): void;
31
31
  */
32
32
  export declare function useUsbDkBackend(): void;
33
33
 
34
+ export declare function _supportedHotplugEvents(): number;
34
35
  export declare function _enableHotplugEvents(): void;
35
36
  export declare function _disableHotplugEvents(): void;
36
37
  export declare function _getLibusbCapability(capability: number): number;
package/tsc/usb/index.ts CHANGED
@@ -26,6 +26,8 @@ declare module './bindings' {
26
26
  interface DeviceEvents extends EventListeners<DeviceEvents> {
27
27
  attach: Device;
28
28
  detach: Device;
29
+ attachIds: undefined;
30
+ detachIds: undefined;
29
31
  }
30
32
 
31
33
  function addListener<K extends keyof DeviceEvents>(event: K, listener: (arg: DeviceEvents[K]) => void): void;
@@ -40,20 +42,13 @@ declare module './bindings' {
40
42
  function listenerCount<K extends keyof DeviceEvents>(event: K): number;
41
43
  }
42
44
 
43
- // Polling mechanism for discovering device changes until this is fixed:
44
- // https://github.com/libusb/libusb/issues/86
45
+ // Polling mechanism for discovering device changes where hotplug detection is not available
45
46
  const pollTimeout = 500;
46
- const hotplugSupported = usb._getLibusbCapability(usb.LIBUSB_CAP_HAS_HOTPLUG) > 0;
47
+ const hotplugSupported = usb._supportedHotplugEvents();
47
48
  let pollingHotplug = false;
48
49
  let pollDevices = new Set<usb.Device>();
49
50
 
50
- const pollHotplug = (start = false) => {
51
- if (start) {
52
- pollingHotplug = true;
53
- } else if (!pollingHotplug) {
54
- return;
55
- }
56
-
51
+ const pollHotplugOnce = (start: boolean) => {
57
52
  // Collect current devices
58
53
  const devices = new Set(usb.getDeviceList());
59
54
 
@@ -72,11 +67,34 @@ const pollHotplug = (start = false) => {
72
67
  }
73
68
 
74
69
  pollDevices = devices;
70
+ };
71
+
72
+ const pollHotplugLoop = (start = false) => {
73
+ if (start) {
74
+ pollingHotplug = true;
75
+ } else if (!pollingHotplug) {
76
+ return;
77
+ }
78
+
79
+ pollHotplugOnce(start);
80
+
75
81
  setTimeout(() => {
76
- pollHotplug();
82
+ pollHotplugLoop();
77
83
  }, pollTimeout);
78
84
  };
79
85
 
86
+ const hotplugModeIsIdsOnly = hotplugSupported === 2;
87
+ if (hotplugModeIsIdsOnly) {
88
+ // The hotplug backend doesnt emit 'attach' or 'detach', so we need to do some conversion
89
+ const hotplugEventConversion = () => {
90
+ // Future: This might want a debounce, to avoid doing multiple polls when attaching a usb hub or something
91
+ pollHotplugOnce(false);
92
+ };
93
+
94
+ usb.on('attachIds', hotplugEventConversion);
95
+ usb.on('detachIds', hotplugEventConversion);
96
+ }
97
+
80
98
  usb.on('newListener', event => {
81
99
  if (event !== 'attach' && event !== 'detach') {
82
100
  return;
@@ -86,7 +104,7 @@ usb.on('newListener', event => {
86
104
  if (hotplugSupported) {
87
105
  usb._enableHotplugEvents();
88
106
  } else {
89
- pollHotplug(true);
107
+ pollHotplugLoop(true);
90
108
  }
91
109
  }
92
110
  });