rawhid 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,328 @@
1
+ /* Simple Raw HID functions for Windows - for use with Teensy RawHID example
2
+ * http://www.pjrc.com/teensy/rawhid.html
3
+ * Copyright (c) 2009 PJRC.COM, LLC
4
+ *
5
+ * rawhid_open - open 1 or more devices
6
+ * rawhid_recv - receive a packet
7
+ * rawhid_send - send a packet
8
+ * rawhid_close - close a device
9
+ *
10
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ * of this software and associated documentation files (the "Software"), to deal
12
+ * in the Software without restriction, including without limitation the rights
13
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ * copies of the Software, and to permit persons to whom the Software is
15
+ * furnished to do so, subject to the following conditions:
16
+ *
17
+ * The above description, website URL and copyright notice and this permission
18
+ * notice shall be included in all copies or substantial portions of the Software.
19
+ *
20
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
+ * THE SOFTWARE.
27
+ *
28
+ * Version 1.0: Initial Release
29
+ */
30
+
31
+ #include <stdio.h>
32
+ #include <stdlib.h>
33
+ #include <stdint.h>
34
+ #include <windows.h>
35
+ #include <setupapi.h>
36
+ #include <ddk/hidsdi.h>
37
+ #include <ddk/hidclass.h>
38
+
39
+ #include "hid.h"
40
+
41
+
42
+ // a list of all opened HID devices, so the caller can
43
+ // simply refer to them by number
44
+ typedef struct hid_struct hid_t;
45
+ static hid_t *first_hid = NULL;
46
+ static hid_t *last_hid = NULL;
47
+ struct hid_struct {
48
+ HANDLE handle;
49
+ int open;
50
+ struct hid_struct *prev;
51
+ struct hid_struct *next;
52
+ };
53
+ static HANDLE rx_event=NULL;
54
+ static HANDLE tx_event=NULL;
55
+ static CRITICAL_SECTION rx_mutex;
56
+ static CRITICAL_SECTION tx_mutex;
57
+
58
+
59
+ // private functions, not intended to be used from outside this file
60
+ static void add_hid(hid_t *h);
61
+ static hid_t * get_hid(int num);
62
+ static void free_all_hid(void);
63
+ static void hid_close(hid_t *hid);
64
+ void print_win32_err(void);
65
+
66
+
67
+
68
+
69
+ // rawhid_recv - receive a packet
70
+ // Inputs:
71
+ // num = device to receive from (zero based)
72
+ // buf = buffer to receive packet
73
+ // len = buffer's size
74
+ // timeout = time to wait, in milliseconds
75
+ // Output:
76
+ // number of bytes received, or -1 on error
77
+ //
78
+ int rawhid_recv(int num, void *buf, int len, int timeout)
79
+ {
80
+ hid_t *hid;
81
+ unsigned char tmpbuf[516];
82
+ OVERLAPPED ov;
83
+ DWORD n, r;
84
+
85
+ if (sizeof(tmpbuf) < len + 1) return -1;
86
+ hid = get_hid(num);
87
+ if (!hid || !hid->open) return -1;
88
+ EnterCriticalSection(&rx_mutex);
89
+ ResetEvent(&rx_event);
90
+ memset(&ov, 0, sizeof(ov));
91
+ ov.hEvent = rx_event;
92
+ if (!ReadFile(hid->handle, tmpbuf, len + 1, NULL, &ov)) {
93
+ if (GetLastError() != ERROR_IO_PENDING) goto return_error;
94
+ r = WaitForSingleObject(rx_event, timeout);
95
+ if (r == WAIT_TIMEOUT) goto return_timeout;
96
+ if (r != WAIT_OBJECT_0) goto return_error;
97
+ }
98
+ if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) goto return_error;
99
+ LeaveCriticalSection(&rx_mutex);
100
+ if (n <= 0) return -1;
101
+ n--;
102
+ if (n > len) n = len;
103
+ memcpy(buf, tmpbuf + 1, n);
104
+ return n;
105
+ return_timeout:
106
+ CancelIo(hid->handle);
107
+ LeaveCriticalSection(&rx_mutex);
108
+ return 0;
109
+ return_error:
110
+ print_win32_err();
111
+ LeaveCriticalSection(&rx_mutex);
112
+ return -1;
113
+ }
114
+
115
+ // rawhid_send - send a packet
116
+ // Inputs:
117
+ // num = device to transmit to (zero based)
118
+ // buf = buffer containing packet to send
119
+ // len = number of bytes to transmit
120
+ // timeout = time to wait, in milliseconds
121
+ // Output:
122
+ // number of bytes sent, or -1 on error
123
+ //
124
+ int rawhid_send(int num, void *buf, int len, int timeout)
125
+ {
126
+ hid_t *hid;
127
+ unsigned char tmpbuf[516];
128
+ OVERLAPPED ov;
129
+ DWORD n, r;
130
+
131
+ if (sizeof(tmpbuf) < len + 1) return -1;
132
+ hid = get_hid(num);
133
+ if (!hid || !hid->open) return -1;
134
+ EnterCriticalSection(&tx_mutex);
135
+ ResetEvent(&tx_event);
136
+ memset(&ov, 0, sizeof(ov));
137
+ ov.hEvent = tx_event;
138
+ tmpbuf[0] = 0;
139
+ memcpy(tmpbuf + 1, buf, len);
140
+ if (!WriteFile(hid->handle, tmpbuf, len + 1, NULL, &ov)) {
141
+ if (GetLastError() != ERROR_IO_PENDING) goto return_error;
142
+ r = WaitForSingleObject(tx_event, timeout);
143
+ if (r == WAIT_TIMEOUT) goto return_timeout;
144
+ if (r != WAIT_OBJECT_0) goto return_error;
145
+ }
146
+ if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) goto return_error;
147
+ LeaveCriticalSection(&tx_mutex);
148
+ if (n <= 0) return -1;
149
+ return n - 1;
150
+ return_timeout:
151
+ CancelIo(hid->handle);
152
+ LeaveCriticalSection(&tx_mutex);
153
+ return 0;
154
+ return_error:
155
+ print_win32_err();
156
+ LeaveCriticalSection(&tx_mutex);
157
+ return -1;
158
+ }
159
+
160
+ // rawhid_open - open 1 or more devices
161
+ //
162
+ // Inputs:
163
+ // max = maximum number of devices to open
164
+ // vid = Vendor ID, or -1 if any
165
+ // pid = Product ID, or -1 if any
166
+ // usage_page = top level usage page, or -1 if any
167
+ // usage = top level usage number, or -1 if any
168
+ // Output:
169
+ // actual number of devices opened
170
+ //
171
+ int rawhid_open(int max, int vid, int pid, int usage_page, int usage)
172
+ {
173
+ GUID guid;
174
+ HDEVINFO info;
175
+ DWORD index=0, reqd_size;
176
+ SP_DEVICE_INTERFACE_DATA iface;
177
+ SP_DEVICE_INTERFACE_DETAIL_DATA *details;
178
+ HIDD_ATTRIBUTES attrib;
179
+ PHIDP_PREPARSED_DATA hid_data;
180
+ HIDP_CAPS capabilities;
181
+ HANDLE h;
182
+ BOOL ret;
183
+ hid_t *hid;
184
+ int count=0;
185
+
186
+ if (first_hid) free_all_hid();
187
+ if (max < 1) return 0;
188
+ if (!rx_event) {
189
+ rx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
190
+ tx_event = CreateEvent(NULL, TRUE, TRUE, NULL);
191
+ InitializeCriticalSection(&rx_mutex);
192
+ InitializeCriticalSection(&tx_mutex);
193
+ }
194
+ HidD_GetHidGuid(&guid);
195
+ info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
196
+ if (info == INVALID_HANDLE_VALUE) return 0;
197
+ for (index=0; 1 ;index++) {
198
+ iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
199
+ ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
200
+ if (!ret) return count;
201
+ SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &reqd_size, NULL);
202
+ details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(reqd_size);
203
+ if (details == NULL) continue;
204
+
205
+ memset(details, 0, reqd_size);
206
+ details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
207
+ ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
208
+ reqd_size, NULL, NULL);
209
+ if (!ret) {
210
+ free(details);
211
+ continue;
212
+ }
213
+ h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
214
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
215
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
216
+ free(details);
217
+ if (h == INVALID_HANDLE_VALUE) continue;
218
+ attrib.Size = sizeof(HIDD_ATTRIBUTES);
219
+ ret = HidD_GetAttributes(h, &attrib);
220
+ //printf("vid: %4x\n", attrib.VendorID);
221
+ if (!ret || (vid > 0 && attrib.VendorID != vid) ||
222
+ (pid > 0 && attrib.ProductID != pid) ||
223
+ !HidD_GetPreparsedData(h, &hid_data)) {
224
+ CloseHandle(h);
225
+ continue;
226
+ }
227
+ if (!HidP_GetCaps(hid_data, &capabilities) ||
228
+ (usage_page > 0 && capabilities.UsagePage != usage_page) ||
229
+ (usage > 0 && capabilities.Usage != usage)) {
230
+ HidD_FreePreparsedData(hid_data);
231
+ CloseHandle(h);
232
+ continue;
233
+ }
234
+ HidD_FreePreparsedData(hid_data);
235
+ hid = (struct hid_struct *)malloc(sizeof(struct hid_struct));
236
+ if (!hid) {
237
+ CloseHandle(h);
238
+ continue;
239
+ }
240
+ hid->handle = h;
241
+ hid->open = 1;
242
+ add_hid(hid);
243
+ count++;
244
+ if (count >= max) return count;
245
+ }
246
+ return count;
247
+ }
248
+
249
+
250
+ // rawhid_close - close a device
251
+ //
252
+ // Inputs:
253
+ // num = device to close (zero based)
254
+ // Output
255
+ // (nothing)
256
+ //
257
+ void rawhid_close(int num)
258
+ {
259
+ hid_t *hid;
260
+
261
+ hid = get_hid(num);
262
+ if (!hid || !hid->open) return;
263
+ hid_close(hid);
264
+ }
265
+
266
+
267
+
268
+ static void add_hid(hid_t *h)
269
+ {
270
+ if (!first_hid || !last_hid) {
271
+ first_hid = last_hid = h;
272
+ h->next = h->prev = NULL;
273
+ return;
274
+ }
275
+ last_hid->next = h;
276
+ h->prev = last_hid;
277
+ h->next = NULL;
278
+ last_hid = h;
279
+ }
280
+
281
+
282
+ static hid_t * get_hid(int num)
283
+ {
284
+ hid_t *p;
285
+ for (p = first_hid; p && num > 0; p = p->next, num--) ;
286
+ return p;
287
+ }
288
+
289
+
290
+ static void free_all_hid(void)
291
+ {
292
+ hid_t *p, *q;
293
+
294
+ for (p = first_hid; p; p = p->next) {
295
+ hid_close(p);
296
+ }
297
+ p = first_hid;
298
+ while (p) {
299
+ q = p;
300
+ p = p->next;
301
+ free(q);
302
+ }
303
+ first_hid = last_hid = NULL;
304
+ }
305
+
306
+
307
+ static void hid_close(hid_t *hid)
308
+ {
309
+ CloseHandle(hid->handle);
310
+ hid->handle = NULL;
311
+ }
312
+
313
+
314
+ void print_win32_err(void)
315
+ {
316
+ char buf[256];
317
+ DWORD err;
318
+
319
+ err = GetLastError();
320
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
321
+ 0, buf, sizeof(buf), NULL);
322
+ printf("err %ld: %s\n", err, buf);
323
+ }
324
+
325
+
326
+
327
+
328
+
@@ -0,0 +1,87 @@
1
+ #include "ruby.h"
2
+ //#include "ext_help.h"
3
+ #include <errno.h>
4
+ #include <inttypes.h>
5
+ #include "hid.h"
6
+
7
+ #define GET_RAWHID(name, val) \
8
+ void *name; \
9
+ Data_Get_Struct(val, void, name)
10
+
11
+ VALUE RawHID;
12
+ VALUE RawHIDError;
13
+
14
+ VALUE RawHID_new(VALUE class, VALUE vendorId, VALUE productId) {
15
+ void *dev = NULL;
16
+ int vId = NUM2INT(vendorId);
17
+ int pId = NUM2INT(pId);
18
+ int devices_opened = rawhid_open(1, &dev, vId, pId, -1, -1);
19
+ if(devices_opened == 0 || dev == NULL) {
20
+ rb_raise(RawHIDError, "Unable to open device");
21
+ }
22
+
23
+ VALUE self = Data_Wrap_Struct(class, NULL, rawhid_close, dev);
24
+ return self;
25
+ }
26
+
27
+ VALUE RawHID_send(int argc, VALUE *argv, VALUE class) {
28
+ VALUE data, timeout_val;
29
+ GET_RAWHID(dev, class);
30
+
31
+ rb_scan_args(argc, argv, "11", &data, &timeout_val);
32
+
33
+ char *buf = StringValuePtr(data);
34
+ int len = RSTRING_LEN(data);
35
+ int timeout = (NIL_P(timeout_val)) ? 0 : NUM2INT(timeout_val);
36
+
37
+ if(len == 0) {
38
+ return INT2NUM(0);
39
+ }
40
+ int sent = rawhid_send(dev, buf, len, timeout);
41
+ if(sent == -1) {
42
+ rb_raise(RawHIDError, "Error sending data to device");
43
+ }
44
+ return INT2NUM(sent);
45
+ }
46
+
47
+ VALUE RawHID_recv(int argc, VALUE *argv, VALUE class) {
48
+ VALUE data, len_val, timeout_val;
49
+ GET_RAWHID(dev, class);
50
+
51
+ rb_scan_args(argc, argv, "11", &len_val, &timeout_val);
52
+
53
+ int len = NUM2INT(len_val);
54
+ int timeout = (NIL_P(timeout_val)) ? 0 : NUM2INT(timeout_val);
55
+ char staticbuf[64];
56
+ char *buf=NULL;
57
+
58
+ if(len <= 64) {
59
+ buf = staticbuf;
60
+ }
61
+ else {
62
+ buf = malloc(len);
63
+ if(!buf) {
64
+ rb_raise(RawHIDError, "Out of memory");
65
+ }
66
+ }
67
+ int received = rawhid_recv(dev, buf, len, timeout);
68
+
69
+ if(received == -1) {
70
+ rb_raise(RawHIDError, "Error receiving data from device");
71
+ }
72
+ data = rb_str_new(buf, received);
73
+ return data;
74
+ }
75
+
76
+ void Init_rawhid() {
77
+ RawHID = rb_define_class("RawHID", rb_cObject);
78
+ RawHIDError = rb_define_class_under(RawHID, "RawHIDError", rb_eRuntimeError);
79
+
80
+ rb_define_singleton_method(RawHID, "new", RawHID_new, 2);
81
+ rb_define_method(RawHID, "send", RawHID_send, -1);
82
+ rb_define_method(RawHID, "recv", RawHID_recv, -1);
83
+
84
+ }
85
+
86
+
87
+
@@ -0,0 +1,100 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <stdarg.h>
4
+
5
+ #if defined(OS_LINUX) || defined(OS_MACOSX)
6
+ #include <sys/ioctl.h>
7
+ #include <termios.h>
8
+ #elif defined(OS_WINDOWS)
9
+ #include <conio.h>
10
+ #endif
11
+
12
+ #include "hid.h"
13
+
14
+
15
+ static char get_keystroke(void);
16
+
17
+
18
+ int main()
19
+ {
20
+ int i, r, num;
21
+ char c, buf[64];
22
+
23
+ // C-based example is 16C0:0480:FFAB:0200
24
+ r = rawhid_open(1, 0x16C0, 0x0480, 0xFFAB, 0x0200);
25
+ if (r <= 0) {
26
+ // Arduino-based example is 16C0:0486:FFAB:0200
27
+ r = rawhid_open(1, 0x16C0, 0x0486, 0xFFAB, 0x0200);
28
+ if (r <= 0) {
29
+ printf("no rawhid device found\n");
30
+ return -1;
31
+ }
32
+ }
33
+ printf("found rawhid device\n");
34
+
35
+ while (1) {
36
+ // check if any Raw HID packet has arrived
37
+ num = rawhid_recv(0, buf, 64, 220);
38
+ if (num < 0) {
39
+ printf("\nerror reading, device went offline\n");
40
+ rawhid_close(0);
41
+ return 0;
42
+ }
43
+ if (num > 0) {
44
+ printf("\nrecv %d bytes:\n", num);
45
+ for (i=0; i<num; i++) {
46
+ printf("%02X ", buf[i] & 255);
47
+ if (i % 16 == 15 && i < num-1) printf("\n");
48
+ }
49
+ printf("\n");
50
+ }
51
+ // check if any input on stdin
52
+ while ((c = get_keystroke()) >= 32) {
53
+ printf("\ngot key '%c', sending...\n", c);
54
+ buf[0] = c;
55
+ for (i=1; i<64; i++) {
56
+ buf[i] = 0;
57
+ }
58
+ rawhid_send(0, buf, 64, 100);
59
+ }
60
+ }
61
+ }
62
+
63
+ #if defined(OS_LINUX) || defined(OS_MACOSX)
64
+ // Linux (POSIX) implementation of _kbhit().
65
+ // Morgan McGuire, morgan@cs.brown.edu
66
+ static int _kbhit() {
67
+ static const int STDIN = 0;
68
+ static int initialized = 0;
69
+ int bytesWaiting;
70
+
71
+ if (!initialized) {
72
+ // Use termios to turn off line buffering
73
+ struct termios term;
74
+ tcgetattr(STDIN, &term);
75
+ term.c_lflag &= ~ICANON;
76
+ tcsetattr(STDIN, TCSANOW, &term);
77
+ setbuf(stdin, NULL);
78
+ initialized = 1;
79
+ }
80
+ ioctl(STDIN, FIONREAD, &bytesWaiting);
81
+ return bytesWaiting;
82
+ }
83
+ static char _getch(void) {
84
+ char c;
85
+ if (fread(&c, 1, 1, stdin) < 1) return 0;
86
+ return c;
87
+ }
88
+ #endif
89
+
90
+
91
+ static char get_keystroke(void)
92
+ {
93
+ if (_kbhit()) {
94
+ char c = _getch();
95
+ if (c >= 32) return c;
96
+ }
97
+ return 0;
98
+ }
99
+
100
+
@@ -0,0 +1,3 @@
1
+ class RawHID
2
+ VERSION = "0.1.1"
3
+ end
data/lib/rawhid.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "rawhid/version"
2
+ require "rawhid/rawhid"
data/rawhid.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rawhid/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rawhid"
8
+ spec.version = RawHID::VERSION
9
+ spec.authors = ["Leo P."]
10
+ spec.email = ["junk@slact.net"]
11
+
12
+ spec.summary = "Ruby binding for Teensy RawHID C code"
13
+ spec.description = "same as above"
14
+ spec.homepage = ""
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.extensions = ["ext/rawhid/extconf.rb"]
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.15"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake-compiler"
29
+ spec.add_development_dependency "pry"
30
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rawhid
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Leo P.
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: same as above
70
+ email:
71
+ - junk@slact.net
72
+ executables: []
73
+ extensions:
74
+ - ext/rawhid/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - CODE_OF_CONDUCT.md
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/setup
85
+ - ext/rawhid/Makefile
86
+ - ext/rawhid/Makefile.bundled
87
+ - ext/rawhid/extconf.h
88
+ - ext/rawhid/extconf.rb
89
+ - ext/rawhid/hid.h
90
+ - ext/rawhid/hid_LINUX.c
91
+ - ext/rawhid/hid_MACOSX.c
92
+ - ext/rawhid/hid_WINDOWS.c
93
+ - ext/rawhid/rawhid.c
94
+ - ext/rawhid/rawhid_test.c
95
+ - lib/rawhid.rb
96
+ - lib/rawhid/version.rb
97
+ - rawhid.gemspec
98
+ homepage: ''
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.6.13
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Ruby binding for Teensy RawHID C code
122
+ test_files: []