usb 2.4.2 → 2.5.1

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.
package/src/helpers.h CHANGED
@@ -10,55 +10,55 @@
10
10
  const napi_property_attributes CONST_PROP = static_cast<napi_property_attributes>(napi_enumerable | napi_configurable);
11
11
 
12
12
  #define ENTER_CONSTRUCTOR(MIN_ARGS) \
13
- Napi::HandleScope scope(env); \
14
- if (!info.IsConstructCall()) throw Napi::Error::New(env, "Must be called with `new`!"); \
15
- CHECK_N_ARGS(MIN_ARGS);
13
+ Napi::HandleScope scope(env); \
14
+ if (!info.IsConstructCall()) throw Napi::Error::New(env, "Must be called with `new`!"); \
15
+ CHECK_N_ARGS(MIN_ARGS);
16
16
 
17
17
  #define ENTER_CONSTRUCTOR_POINTER(CLASS, MIN_ARGS) \
18
- ENTER_CONSTRUCTOR(MIN_ARGS) \
19
- if (!info.Length() || !info[0].IsExternal()){ \
20
- throw Napi::Error::New(env, "This type cannot be created directly!"); \
21
- } \
22
- auto self = this;
18
+ ENTER_CONSTRUCTOR(MIN_ARGS) \
19
+ if (!info.Length() || !info[0].IsExternal()){ \
20
+ throw Napi::Error::New(env, "This type cannot be created directly!"); \
21
+ } \
22
+ auto self = this;
23
23
 
24
24
  #define ENTER_METHOD(CLASS, MIN_ARGS) \
25
- Napi::Env env = info.Env(); \
26
- Napi::HandleScope scope(env); \
27
- CHECK_N_ARGS(MIN_ARGS); \
28
- auto self = this;
25
+ Napi::Env env = info.Env(); \
26
+ Napi::HandleScope scope(env); \
27
+ CHECK_N_ARGS(MIN_ARGS); \
28
+ auto self = this;
29
29
 
30
30
  #define ENTER_ACCESSOR(CLASS) \
31
- Napi::HandleScope scope(env); \
32
- auto self = info.Holder().Unwrap<CLASS>();
31
+ Napi::HandleScope scope(env); \
32
+ auto self = info.Holder().Unwrap<CLASS>();
33
33
 
34
34
  #define UNWRAP_ARG(CLASS, NAME, ARGNO) \
35
- if (!info[ARGNO].IsObject()) \
36
- THROW_BAD_ARGS("Parameter " #NAME " is not an object"); \
37
- auto NAME = Napi::ObjectWrap<CLASS>::Unwrap(info[ARGNO].As<Napi::Object>()); \
38
- if (!NAME) \
39
- THROW_BAD_ARGS("Parameter " #NAME " (" #ARGNO ") is of incorrect type");
35
+ if (!info[ARGNO].IsObject()) \
36
+ THROW_BAD_ARGS("Parameter " #NAME " is not an object"); \
37
+ auto NAME = Napi::ObjectWrap<CLASS>::Unwrap(info[ARGNO].As<Napi::Object>()); \
38
+ if (!NAME) \
39
+ THROW_BAD_ARGS("Parameter " #NAME " (" #ARGNO ") is of incorrect type");
40
40
 
41
41
  #define STRING_ARG(NAME, N) \
42
- if (info.Length() > N){ \
43
- if (!info[N].IsString()) \
44
- THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be string"); \
45
- NAME = *String::Utf8Value(info[N].ToString()); \
46
- }
42
+ if (info.Length() > N){ \
43
+ if (!info[N].IsString()) \
44
+ THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be string"); \
45
+ NAME = *String::Utf8Value(info[N].ToString()); \
46
+ }
47
47
 
48
48
  #define DOUBLE_ARG(NAME, N) \
49
- if (!info[N].IsNumber()) \
50
- THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be number"); \
51
- NAME = info[N].ToNumber()->Value();
49
+ if (!info[N].IsNumber()) \
50
+ THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be number"); \
51
+ NAME = info[N].ToNumber()->Value();
52
52
 
53
53
  #define INT_ARG(NAME, N) \
54
- if (!info[N].IsNumber()) \
55
- THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be number"); \
56
- NAME = info[N].As<Napi::Number>().Int32Value();
54
+ if (!info[N].IsNumber()) \
55
+ THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be number"); \
56
+ NAME = info[N].As<Napi::Number>().Int32Value();
57
57
 
58
58
  #define BOOL_ARG(NAME, N) \
59
- NAME = false; \
60
- if (info.Length() > N){ \
61
- if (!info[N].IsBoolean()) \
62
- THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be bool"); \
63
- NAME = info[N].ToBoolean()->Value(); \
64
- }
59
+ NAME = false; \
60
+ if (info.Length() > N){ \
61
+ if (!info[N].IsBoolean()) \
62
+ THROW_BAD_ARGS("Parameter " #NAME " (" #N ") should be bool"); \
63
+ NAME = info[N].ToBoolean()->Value(); \
64
+ }
@@ -0,0 +1,22 @@
1
+ #ifndef _USB_HOTPLUG_H
2
+ #define _USB_HOTPLUG_H
3
+
4
+ #include "../node_usb.h"
5
+
6
+ #define HOTPLUG_SUPPORTS_NONE 0
7
+ #define HOTPLUG_SUPPORTS_DEVICES 1
8
+ #define HOTPLUG_SUPPORTS_IDS 2
9
+
10
+ class HotPlugManager {
11
+ public:
12
+ static std::unique_ptr<HotPlugManager> create();
13
+
14
+ virtual int supportedHotplugEvents() = 0;
15
+
16
+ virtual void enableHotplug(const Napi::Env& env, ModuleData* instanceData) = 0;
17
+ virtual void disableHotplug(const Napi::Env& env, ModuleData* instanceData) = 0;
18
+ };
19
+
20
+ void handleHotplug(HotPlug* info);
21
+
22
+ #endif
@@ -0,0 +1,90 @@
1
+ #include "hotplug.h"
2
+
3
+ struct HotPlug {
4
+ libusb_device* device;
5
+ libusb_hotplug_event event;
6
+ Napi::ObjectReference* hotplugThis;
7
+ };
8
+
9
+ int LIBUSB_CALL hotplug_callback(libusb_context* ctx, libusb_device* device, libusb_hotplug_event event, void* user_data) {
10
+ libusb_ref_device(device);
11
+ ModuleData* instanceData = (ModuleData*)user_data;
12
+ instanceData->hotplugQueue.post(new HotPlug {device, event, &instanceData->hotplugThis});
13
+ return 0;
14
+ }
15
+
16
+ class HotPlugManagerLibUsb: public HotPlugManager {
17
+ int supportedHotplugEvents() {
18
+ int res = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
19
+
20
+ return res > 0 ? HOTPLUG_SUPPORTS_DEVICES : HOTPLUG_SUPPORTS_NONE;
21
+ }
22
+
23
+ void enableHotplug(const Napi::Env& env, ModuleData* instanceData) {
24
+ libusb_context* usb_context = instanceData->usb_context;
25
+ CHECK_USB(libusb_hotplug_register_callback(
26
+ usb_context,
27
+ (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
28
+ (libusb_hotplug_flag)0,
29
+ LIBUSB_HOTPLUG_MATCH_ANY,
30
+ LIBUSB_HOTPLUG_MATCH_ANY,
31
+ LIBUSB_HOTPLUG_MATCH_ANY,
32
+ hotplug_callback,
33
+ instanceData,
34
+ &hotplugHandle
35
+ ));
36
+ }
37
+
38
+ void disableHotplug(const Napi::Env& env, ModuleData* instanceData) {
39
+ libusb_context* usb_context = instanceData->usb_context;
40
+ libusb_hotplug_deregister_callback(usb_context, hotplugHandle);
41
+ }
42
+
43
+ libusb_hotplug_callback_handle hotplugHandle;
44
+ };
45
+
46
+ std::unique_ptr<HotPlugManager> HotPlugManager::create() {
47
+ return std::make_unique<HotPlugManagerLibUsb>();
48
+ }
49
+
50
+ void handleHotplug(HotPlug* info) {
51
+ Napi::ObjectReference* hotplugThis = info->hotplugThis;
52
+ Napi::Env env = hotplugThis->Env();
53
+ Napi::HandleScope scope(env);
54
+
55
+ libusb_device* dev = info->device;
56
+ libusb_hotplug_event event = info->event;
57
+ delete info;
58
+
59
+ DEBUG_LOG("HandleHotplug %p %i", dev, event);
60
+
61
+ Napi::Object v8dev = Device::get(env, dev);
62
+ libusb_unref_device(dev);
63
+
64
+ Napi::Object v8VidPid = Napi::Object::New(env);
65
+ auto deviceDescriptor = v8dev.Get("deviceDescriptor");
66
+ if (deviceDescriptor.IsObject()) {
67
+ v8VidPid.Set("idVendor", deviceDescriptor.As<Napi::Object>().Get("idVendor"));
68
+ v8VidPid.Set("idProduct", deviceDescriptor.As<Napi::Object>().Get("idProduct"));
69
+ }
70
+
71
+ Napi::String eventName;
72
+ Napi::String changeEventName;
73
+ if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) {
74
+ DEBUG_LOG("Device arrived");
75
+ eventName = Napi::String::New(env, "attach");
76
+ changeEventName = Napi::String::New(env, "attachIds");
77
+
78
+ } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) {
79
+ DEBUG_LOG("Device left");
80
+ eventName = Napi::String::New(env, "detach");
81
+ changeEventName = Napi::String::New(env, "detachIds");
82
+
83
+ } else {
84
+ DEBUG_LOG("Unhandled hotplug event %d\n", event);
85
+ return;
86
+ }
87
+
88
+ hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { eventName, v8dev });
89
+ hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { changeEventName, v8VidPid });
90
+ }
@@ -0,0 +1,161 @@
1
+ #include "hotplug.h"
2
+
3
+ // Include Windows headers
4
+ #include <windows.h>
5
+ #include <initguid.h>
6
+ #include <Cfgmgr32.h>
7
+ #include <usbiodef.h>
8
+
9
+ #include <locale>
10
+ #include <codecvt>
11
+ #include <cwctype>
12
+
13
+ #define VID_TAG L"VID_"
14
+ #define PID_TAG L"PID_"
15
+
16
+ struct HotPlug {
17
+ int vid;
18
+ int pid;
19
+ CM_NOTIFY_ACTION event;
20
+ Napi::ObjectReference* hotplugThis;
21
+ };
22
+
23
+ void extractVidPid(wchar_t *buf, int *vid, int *pid)
24
+ {
25
+ // Example input: \\?\USB#VID_0FD9&PID_0060#000000000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
26
+
27
+ *vid = 0;
28
+ *pid = 0;
29
+
30
+ if (buf == NULL)
31
+ {
32
+ return;
33
+ }
34
+
35
+ auto string = std::wstring(buf);
36
+ std::transform(string.begin(), string.end(), string.begin(), std::towupper);
37
+
38
+ wchar_t* temp = new wchar_t[5];
39
+ temp[4] = L'\0';
40
+
41
+ const wchar_t *vidStr = wcsstr(string.data(), VID_TAG);
42
+ const wchar_t *pidStr = wcsstr(string.data(), PID_TAG);
43
+
44
+ if (vidStr != nullptr)
45
+ {
46
+ memcpy(temp, vidStr + wcslen(VID_TAG), 4 * sizeof(wchar_t));
47
+ *vid = wcstol(temp, NULL, 16);
48
+ }
49
+
50
+ if (pidStr != nullptr)
51
+ {
52
+ memcpy(temp, pidStr + wcslen(PID_TAG), 4 * sizeof(wchar_t));
53
+ *pid = wcstol(temp, NULL, 16);
54
+ }
55
+ }
56
+
57
+ DWORD MyCMInterfaceNotification(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize)
58
+ {
59
+ switch (Action)
60
+ {
61
+ case CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL:
62
+ case CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL:
63
+ {
64
+ ModuleData* instanceData = (ModuleData*)Context;
65
+
66
+ int vid = 0;
67
+ int pid = 0;
68
+ extractVidPid(EventData->u.DeviceInterface.SymbolicLink, &vid, &pid);
69
+
70
+ instanceData->hotplugQueue.post(new HotPlug {vid, pid, Action, &instanceData->hotplugThis});
71
+ break;
72
+ }
73
+ default:
74
+ break;
75
+ }
76
+ return 0;
77
+ }
78
+
79
+ class HotPlugManagerWindows : public HotPlugManager
80
+ {
81
+ int supportedHotplugEvents()
82
+ {
83
+ return HOTPLUG_SUPPORTS_IDS;
84
+ }
85
+
86
+ void enableHotplug(const Napi::Env &env, ModuleData *instanceData)
87
+ {
88
+ if (isRunning)
89
+ {
90
+ return;
91
+ }
92
+
93
+ isRunning = true;
94
+
95
+ CM_NOTIFY_FILTER cmNotifyFilter = { 0 };
96
+ cmNotifyFilter.cbSize = sizeof(cmNotifyFilter);
97
+ cmNotifyFilter.Flags = 0;
98
+ cmNotifyFilter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
99
+ cmNotifyFilter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_USB_DEVICE;
100
+
101
+ auto res = CM_Register_Notification(&cmNotifyFilter, (PVOID)instanceData, (PCM_NOTIFY_CALLBACK)&MyCMInterfaceNotification, &hcm);
102
+ if (res != CR_SUCCESS)
103
+ {
104
+ THROW_ERROR("RegisterNotification failed")
105
+ }
106
+ }
107
+
108
+ void disableHotplug(const Napi::Env &env, ModuleData *instanceData)
109
+ {
110
+ if (isRunning)
111
+ {
112
+ isRunning = false;
113
+
114
+ if (hcm) {
115
+ CM_Unregister_Notification(hcm);
116
+ hcm = nullptr;
117
+ }
118
+ }
119
+ }
120
+
121
+ private:
122
+ std::atomic<bool> isRunning = {false};
123
+ HCMNOTIFICATION hcm;
124
+ };
125
+
126
+ std::unique_ptr<HotPlugManager> HotPlugManager::create()
127
+ {
128
+ return std::make_unique<HotPlugManagerWindows>();
129
+ }
130
+
131
+ void handleHotplug(HotPlug* info) {
132
+ Napi::ObjectReference* hotplugThis = info->hotplugThis;
133
+ Napi::Env env = hotplugThis->Env();
134
+ Napi::HandleScope scope(env);
135
+
136
+ int vid = info->vid;
137
+ int pid = info->pid;
138
+ Napi::Object v8VidPid = Napi::Object::New(env);
139
+ v8VidPid.Set("idVendor", Napi::Number::New(env, vid));
140
+ v8VidPid.Set("idProduct", Napi::Number::New(env, pid));
141
+ CM_NOTIFY_ACTION event = info->event;
142
+ delete info;
143
+
144
+ DEBUG_LOG("HandleHotplug %i %i %i", vid, pid, event);
145
+
146
+ Napi::String eventName;
147
+ if (CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL == event) {
148
+ DEBUG_LOG("Device arrived");
149
+ eventName = Napi::String::New(env, "attachIds");
150
+
151
+ } else if (CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL == event) {
152
+ DEBUG_LOG("Device left");
153
+ eventName = Napi::String::New(env, "detachIds");
154
+
155
+ } else {
156
+ DEBUG_LOG("Unhandled hotplug event %d\n", event);
157
+ return;
158
+ }
159
+
160
+ hotplugThis->Get("emit").As<Napi::Function>().MakeCallback(hotplugThis->Value(), { eventName, v8VidPid });
161
+ }