Commit | Line | Data |
---|---|---|
c099d658 | 1 | /** |
2 | * USB HID relays API library | |
3 | * http://git.io/bGcxrQ | |
4 | * | |
5132ecf9 | 5 | * This is reconstruction of the original Windows DLL, |
63e45858 P |
6 | * as supplied by the USB relay vendors. |
7 | * It is binary compatible and works with their example programs. | |
8 | * The original usb_relay_device.h file has been slightly hacked up. | |
9 | * | |
c099d658 | 10 | * 12-jan-2015 pa01 Win32 version |
11 | */ | |
12 | ||
13 | #define MY_VERSION 0x02 | |
14 | ||
15 | #if defined (WIN32) || defined (_WIN32) | |
16 | ||
17 | // Windows 32 or 64 bit | |
18 | #include "targetver.h" | |
63e45858 | 19 | #define WIN32_EXTRALEAN |
c099d658 | 20 | #include <windows.h> |
21 | ||
5132ecf9 | 22 | #ifdef _MSC_VER |
63e45858 P |
23 | /* The original DLL has cdecl calling convention */ |
24 | #define USBRL_CALL __cdecl | |
25 | #define USBRL_API __declspec(dllexport) USBRL_CALL | |
26 | ||
4c51b553 | 27 | #if _MSC_VER < 1900 /* before VS2015 */ |
c099d658 | 28 | #define snprintf _snprintf |
4c51b553 | 29 | #endif /* VS2015 */ |
5132ecf9 | 30 | #endif // _MSC_VER |
c099d658 | 31 | #endif //WIN32 |
32 | ||
33 | #include "usb_relay_device.h" | |
34 | ||
35 | #if USBRELAY_LIB_VER != MY_VERSION | |
36 | #error "Oops. Wrong version of usb_relay_device.h" | |
37 | #endif | |
38 | ||
39 | #include "usb_relay_hw.h" | |
40 | #include "hiddata.h" | |
41 | #include <stdio.h> | |
42 | #include <string.h> | |
43 | #include <stdlib.h> | |
44 | ||
ac36c33b | 45 | //#define dbgprintf(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) |
46 | //#define dbgprintf(fmt, ...) printf(fmt, ## __VA_ARGS__) | |
47 | #define dbgprintf(fmt, ...) //__noop(fmt, __VA_ARGS__) | |
48 | //#define printerr(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) | |
49 | //#define printerr(fmt, ...) printf(fmt, ## __VA_ARGS__) | |
50 | #define printerr(fmt, ...) // __noop(fmt, __VA_ARGS__) | |
c099d658 | 51 | |
52 | #ifdef __cplusplus | |
53 | extern "C" { | |
54 | #endif | |
55 | ||
56 | struct usbrelay_internal_s { | |
57 | struct usb_relay_device_info urdi; //public part | |
58 | // Private part: | |
59 | USBDEVHANDLE usbh; // handle | |
60 | char idstr[8]; | |
61 | }; | |
5132ecf9 | 62 | |
c099d658 | 63 | // struct for enum context |
64 | struct enumctx_s { | |
65 | struct usbrelay_internal_s *head, *tail; | |
66 | int numdevs; | |
67 | int status; | |
68 | }; | |
5132ecf9 | 69 | |
c099d658 | 70 | // Globals |
71 | ||
aeb44a35 | 72 | static const char *g_dummyPath = "NOTHING"; // passing dev.path to client not implemented, I return this as path. |
c099d658 | 73 | |
74 | static const char *usbErrorMessage(int errCode) | |
75 | { | |
76 | static char buffer[80]; | |
77 | buffer[0] = 0; | |
78 | if ( errCode != USBHID_ERR_UNKNOWN ) { | |
79 | usbhidStrerror_r(errCode, buffer, sizeof(buffer)); | |
80 | } | |
81 | if ( 0 == buffer[0] ) { | |
82 | snprintf(buffer, sizeof(buffer), "Unknown error (%d)", errCode); | |
83 | } | |
84 | return buffer; | |
85 | } | |
86 | ||
87 | // Read state of all relays | |
88 | // @return bit mask of all relays (R1->bit 0, R2->bit 1 ...) or -1 on error | |
89 | static int rel_read_status_raw(USBDEVHANDLE dev, void *raw_data) | |
90 | { | |
91 | char buffer[10]; | |
92 | int err; | |
93 | int reportnum = 0; | |
94 | int len = 8 + 1; /* report id 1 byte + 8 bytes data */ | |
95 | memset(buffer, 0, sizeof(buffer)); | |
96 | ||
97 | err = usbhidGetReport(dev, reportnum, buffer, &len); | |
98 | if ( err ) { | |
99 | printerr("error reading status: %s\n", usbErrorMessage(err)); | |
100 | return -1; | |
101 | } | |
102 | ||
103 | if ( len != 9 || buffer[0] != reportnum ) { | |
104 | printerr("ERROR: wrong HID report returned! %d\n", len); | |
105 | return -2; | |
106 | } | |
107 | ||
108 | if (raw_data) { | |
109 | /* copy raw report data */ | |
110 | memcpy( raw_data, buffer, len ); | |
111 | } | |
112 | ||
113 | return (unsigned char)buffer[8]; /* byte of relay states */ | |
114 | } | |
115 | ||
116 | // Turn relay on/off. | |
117 | // @param relaynum: positive (1-N): one relay index, negative: all, -num = number of relays | |
118 | // @returns 0 ok, else error | |
119 | static int rel_onoff( USBDEVHANDLE dev, int is_on, int relaynum ) | |
120 | { | |
121 | unsigned char buffer[10]; | |
122 | int err = -1; | |
123 | unsigned char cmd1, cmd2, mask, maskval; | |
5132ecf9 | 124 | |
c099d658 | 125 | if ( relaynum < 0 && (-relaynum) <= 8 ) { |
126 | mask = 0xFF; | |
127 | cmd2 = 0; | |
128 | if (is_on) { | |
129 | cmd1 = 0xFE; | |
130 | maskval = (unsigned char)( (1U << (-relaynum)) - 1 ); | |
131 | } else { | |
132 | cmd1 = 0xFC; | |
133 | maskval = 0; | |
134 | } | |
135 | } else { | |
136 | if ( relaynum <= 0 || relaynum > 8 ) { | |
137 | printerr("Relay number must be 1-8\n"); | |
138 | return 1; | |
139 | } | |
904823f7 | 140 | mask = (unsigned char)(1U << (relaynum-1)); |
c099d658 | 141 | cmd2 = (unsigned char)relaynum; |
142 | if (is_on) { | |
143 | cmd1 = 0xFF; | |
144 | maskval = mask; | |
145 | } else { | |
146 | cmd1 = 0xFD; | |
147 | maskval = 0; | |
148 | } | |
149 | } | |
150 | ||
151 | memset(buffer, 0, sizeof(buffer)); | |
152 | buffer[0] = 0; /* report # */ | |
153 | buffer[1] = cmd1; | |
154 | buffer[2] = cmd2; | |
155 | if((err = usbhidSetReport(dev, (void*)buffer, 9)) != 0) { | |
156 | printerr("Error writing data: %s\n", usbErrorMessage(err)); | |
157 | return 1; | |
158 | } | |
5132ecf9 | 159 | |
c099d658 | 160 | // Read back & verify |
161 | err = rel_read_status_raw(dev, NULL); | |
162 | if ( err < 0 ) { | |
163 | printerr("Error read back: %s\n", usbErrorMessage(err)); | |
164 | return 1; | |
165 | } | |
166 | ||
167 | err = err & mask; | |
5132ecf9 | 168 | if (err != maskval) { |
c099d658 | 169 | printerr("Error: failed to set relay %u %s\n", relaynum, is_on ? "ON":"OFF"); |
170 | return 1; | |
171 | } | |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
176 | ||
177 | // Public functions: | |
178 | ||
179 | /** Initialize the USB Relay Library | |
180 | @returns: This function returns 0 on success and -1 on error. | |
181 | */ | |
182 | int USBRL_API usb_relay_init(void) | |
183 | { | |
184 | return 0; | |
185 | } | |
186 | ||
187 | /** Finalize the USB Relay Library. | |
5132ecf9 | 188 | This function frees all of the static data associated with USB Relay Library. |
c099d658 | 189 | It should be called at the end of execution to avoid memory leaks. |
190 | @returns: This function returns 0 on success and -1 on error. | |
191 | */ | |
192 | int USBRL_API usb_relay_exit(void) | |
193 | { | |
194 | return 0; | |
195 | } | |
196 | ||
197 | // Enum function for building list of devices | |
5132ecf9 | 198 | static |
c099d658 | 199 | int enumfunc(USBDEVHANDLE usbh, void *context) |
200 | { | |
201 | // static const char vendorName[] = USB_RELAY_VENDOR_NAME; | |
202 | static const char productName[] = USB_RELAY_NAME_PREF; | |
203 | int err; | |
204 | char buffer[128*sizeof(short)]; // max USB string is 128 UTF-16 chars | |
205 | int num = 0; | |
206 | int i; | |
207 | struct usbrelay_internal_s *q; | |
208 | struct enumctx_s *ectx = (struct enumctx_s *)context; | |
209 | ||
210 | //NOTE: Ignore vendor string. This is against ObjDev rules, restore the check if needed! | |
211 | ||
212 | err = usbhidGetProductString(usbh, buffer, sizeof(buffer)); | |
213 | if (err) | |
214 | { | |
215 | goto next; | |
216 | } | |
217 | ||
218 | i = (int)strlen(buffer); | |
219 | if ( i != strlen(productName) + 1 ) | |
220 | { | |
221 | goto next; | |
222 | } | |
223 | ||
224 | /* the last char of ProductString is number of relays */ | |
225 | num = (int)(buffer[i - 1]) - (int)'0'; | |
226 | buffer[i - 1] = 0; | |
227 | ||
228 | if ( 0 != strcmp( buffer, productName) ) | |
229 | { | |
230 | goto next; | |
231 | } | |
232 | ||
233 | if ( num <= 0 || num > 8 ) | |
234 | { | |
235 | dbgprintf("Unknown relay device? num relays=%d\n", num); | |
236 | goto next; | |
237 | } | |
238 | ||
239 | /* Check the unique ID: USB_RELAY_ID_STR_LEN bytes at offset 1 (just after the report id) */ | |
240 | err = rel_read_status_raw(usbh, buffer); | |
241 | if( err < 0 ) | |
242 | { | |
243 | dbgprintf("Error reading report 0: %s\n", usbErrorMessage(err)); | |
244 | goto next; | |
245 | } | |
5132ecf9 | 246 | |
c099d658 | 247 | for (i = 1; i <= USB_RELAY_ID_STR_LEN; i++) |
248 | { | |
249 | unsigned char x = (unsigned char)buffer[i]; | |
250 | if (x <= 0x20 || x >= 0x7F) | |
251 | { | |
252 | dbgprintf("Bad usbrelay ID string!\n"); | |
253 | goto next; | |
254 | } | |
255 | } | |
256 | ||
257 | if( buffer[USB_RELAY_ID_STR_LEN + 1] != 0 ) | |
258 | { | |
259 | dbgprintf("Bad usbrelay ID string!\n"); | |
260 | goto next; | |
261 | } | |
262 | ||
263 | dbgprintf("Device %s%d found: ID=[%5s]\n", productName, num, &buffer[1]); | |
264 | ||
265 | // allocate & save info | |
266 | q = (struct usbrelay_internal_s *)calloc(1, sizeof(struct usbrelay_internal_s)); | |
267 | if (!q) { | |
268 | dbgprintf("Malloc err\n"); | |
269 | goto next; //$$$ revise | |
270 | } | |
271 | /* keep this device, continue */ | |
272 | q->usbh = usbh; | |
273 | memcpy(q->idstr, &buffer[1], USB_RELAY_ID_STR_LEN); | |
274 | q->urdi.type = num; // enum = number of relays | |
275 | q->urdi.serial_number = &q->idstr[0]; | |
276 | q->urdi.device_path = (char*)g_dummyPath; | |
277 | ||
278 | if (!ectx->head) { | |
279 | ectx->head = q; | |
280 | ectx->tail =q; | |
281 | } else { | |
282 | ectx->tail->urdi.next = (pusb_relay_device_info_t)q; | |
aeb44a35 | 283 | ectx->tail = q; |
c099d658 | 284 | } |
5132ecf9 | 285 | |
c099d658 | 286 | ++ectx->numdevs; |
287 | return 1; | |
288 | ||
289 | next: | |
290 | /* Continue search */ | |
291 | usbhidCloseDevice(usbh); | |
292 | return 1; | |
293 | } | |
294 | ||
295 | // Enum function for open one device by ID | |
5132ecf9 | 296 | static |
c099d658 | 297 | int enumOpenfunc(USBDEVHANDLE usbh, void *context) |
298 | { | |
299 | // static const char vendorName[] = USB_RELAY_VENDOR_NAME; | |
300 | static const char productName[] = USB_RELAY_NAME_PREF; | |
301 | int err; | |
302 | char buffer[128*sizeof(short)]; // max USB string is 128 UTF-16 chars | |
303 | int num = 0; | |
304 | int i; | |
305 | struct enumctx_s *ectx = (struct enumctx_s *)context; | |
306 | struct usbrelay_internal_s *q = ectx->head; | |
307 | ||
308 | //NOTE: Ignore vendor string. This is against ObjDev rules, restore the check if needed! | |
309 | ||
310 | err = usbhidGetProductString(usbh, buffer, sizeof(buffer)); | |
311 | if (err) | |
312 | { | |
313 | goto next; | |
314 | } | |
315 | ||
316 | i = (int)strlen(buffer); | |
317 | if ( i != strlen(productName) + 1 ) | |
318 | { | |
319 | goto next; | |
320 | } | |
321 | ||
322 | /* the last char of ProductString is number of relays */ | |
323 | num = (int)(buffer[i - 1]) - (int)'0'; | |
324 | buffer[i - 1] = 0; | |
325 | ||
326 | if ( 0 != strcmp( buffer, productName) ) | |
327 | { | |
328 | goto next; | |
329 | } | |
330 | ||
331 | if ( num <= 0 || num > 8 ) | |
332 | { | |
333 | dbgprintf("Unknown relay device? num relays=%d\n", num); | |
334 | goto next; | |
335 | } | |
336 | ||
337 | /* Check the unique ID: USB_RELAY_ID_STR_LEN bytes at offset 1 (just after the report id) */ | |
338 | err = rel_read_status_raw(usbh, buffer); | |
339 | if( err < 0 ) | |
340 | { | |
341 | dbgprintf("Error reading report 0: %s\n", usbErrorMessage(err)); | |
342 | goto next; | |
343 | } | |
5132ecf9 | 344 | |
c099d658 | 345 | for (i = 1; i <= USB_RELAY_ID_STR_LEN; i++) |
346 | { | |
347 | unsigned char x = (unsigned char)buffer[i]; | |
348 | if (x <= 0x20 || x >= 0x7F) | |
349 | { | |
350 | dbgprintf("Bad usbrelay ID string!\n"); | |
351 | goto next; | |
352 | } | |
353 | } | |
354 | ||
355 | if( buffer[USB_RELAY_ID_STR_LEN + 1] != 0 ) | |
356 | { | |
357 | dbgprintf("Bad usbrelay ID string!\n"); | |
358 | goto next; | |
359 | } | |
360 | ||
361 | dbgprintf("Device %s%d found: ID=[%5s]\n", productName, num, &buffer[1]); | |
362 | ||
363 | if ( 0 == memcmp( q->idstr, &buffer[1], USB_RELAY_ID_STR_LEN) ) { | |
364 | q->usbh = usbh; | |
365 | q->urdi.type = num; // enum = number of relays | |
366 | q->urdi.serial_number = &q->idstr[0]; | |
367 | q->urdi.device_path = (char*)g_dummyPath; | |
368 | ++ectx->numdevs; | |
369 | return 0; | |
370 | } | |
371 | ||
372 | next: | |
373 | /* Continue search */ | |
374 | usbhidCloseDevice(usbh); | |
375 | return 1; | |
376 | } | |
377 | ||
378 | /** Enumerate the USB Relay Devices.*/ | |
379 | pusb_relay_device_info_t USBRL_API usb_relay_device_enumerate(void) | |
380 | { | |
381 | struct enumctx_s ectx; | |
382 | int ret; | |
383 | memset(&ectx, 0, sizeof(ectx)); | |
384 | ret = usbhidEnumDevices(USB_CFG_VENDOR_ID, USB_CFG_DEVICE_ID, | |
385 | (void*)&ectx, | |
386 | enumfunc); | |
387 | ||
388 | return (pusb_relay_device_info_t)ectx.head; | |
389 | } | |
390 | ||
391 | ||
392 | /** Free an enumeration Linked List*/ | |
393 | void USBRL_API usb_relay_device_free_enumerate(struct usb_relay_device_info *dilist) | |
394 | { | |
395 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)dilist; | |
396 | ||
397 | while (p) { | |
398 | struct usbrelay_internal_s *q = (struct usbrelay_internal_s *)((pusb_relay_device_info_t)p)->next; | |
399 | if (p->usbh && ((USBDEVHANDLE)(-1)) != p->usbh) { | |
400 | usbhidCloseDevice(p->usbh); | |
401 | p->usbh = 0; | |
402 | } | |
403 | free(p); | |
404 | p = q; | |
405 | } | |
5132ecf9 | 406 | |
c099d658 | 407 | return; |
408 | } | |
409 | ||
410 | /** Open device by serial number | |
411 | serial_number == NULL is valid and means any one device. | |
412 | @return: This function returns a valid handle to the device on success or NULL on failure. | |
413 | Example: usb_relay_device_open_with_serial_number("abcde", 5) */ | |
414 | intptr_t USBRL_API usb_relay_device_open_with_serial_number(const char *serial_number, unsigned len) | |
415 | { | |
416 | struct enumctx_s ectx; | |
417 | int ret; | |
418 | struct usbrelay_internal_s *q; | |
419 | memset(&ectx, 0, sizeof(ectx)); | |
5132ecf9 | 420 | |
c099d658 | 421 | if (serial_number && len != USB_RELAY_ID_STR_LEN) { |
422 | printerr("Specified invalid str id length: %u", len); | |
423 | return (intptr_t)0; | |
424 | } | |
425 | ||
426 | q = ectx.head = calloc(1, sizeof(*ectx.head)); | |
427 | if (!q) | |
428 | return (intptr_t)0; | |
429 | ||
430 | memcpy(q->idstr, serial_number, len); | |
431 | ||
432 | ret = usbhidEnumDevices(USB_CFG_VENDOR_ID, USB_CFG_DEVICE_ID, | |
433 | (void*)&ectx, | |
904823f7 | 434 | enumOpenfunc); |
c099d658 | 435 | if (ret != 0) |
436 | goto ret_err; // error during enum | |
437 | ||
438 | if (ectx.numdevs == 0 || q->usbh == 0) { | |
439 | goto ret_err; // not found | |
440 | } | |
441 | ||
442 | q->urdi.next = (void*)q; // mark this element as standalone | |
443 | return (intptr_t)q; | |
444 | ||
445 | ret_err: | |
446 | free(q); | |
447 | return (intptr_t)0; | |
448 | } | |
449 | ||
450 | /** Open a USB relay device | |
451 | @return: This function returns a valid handle to the device on success or NULL on failure. | |
452 | */ | |
453 | intptr_t USBRL_API usb_relay_device_open(struct usb_relay_device_info *device_info) | |
454 | { | |
455 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)device_info; | |
456 | if (!device_info) | |
457 | return 0; | |
458 | if ( (uintptr_t)p->usbh == 0 || (uintptr_t)p->usbh == (uintptr_t)-1 ) | |
459 | return 0; | |
460 | //$$$ validate more | |
5132ecf9 | 461 | return (uintptr_t)device_info; |
c099d658 | 462 | } |
463 | ||
464 | /** Close a USB relay device*/ | |
465 | void USBRL_API usb_relay_device_close(intptr_t hHandle) | |
466 | { | |
467 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)hHandle; | |
468 | if ( 0 == hHandle || ((intptr_t)-1) == hHandle ) | |
469 | return; | |
470 | ||
471 | if ( (void*)(p->urdi.next) == (void*)p ) { | |
472 | // This was made by usb_relay_device_open_with_serial_number() so free it now: | |
473 | if ( p->usbh && ((intptr_t)-1) != (intptr_t)(p->usbh)) { | |
474 | usbhidCloseDevice(p->usbh); | |
475 | p->usbh = 0; | |
476 | } | |
477 | p->urdi.next = NULL; | |
478 | free( (void*)p ); | |
479 | } | |
480 | // Else this can be in the list, don't do anything. | |
481 | } | |
482 | ||
483 | /** Turn ON a relay channel on the USB-Relay-Device | |
484 | @param index -- which channel your want to open | |
485 | @param hHandle -- which usb relay device your want to operate | |
486 | @returns: 0 -- success; 1 -- error; 2 -- index is outnumber the number of the usb relay device | |
487 | */ | |
488 | int USBRL_API usb_relay_device_open_one_relay_channel(intptr_t hHandle, int index) | |
489 | { | |
490 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)hHandle; | |
491 | if (!p) | |
492 | return 1; | |
493 | if ( index <= 0 || index > (int)p->urdi.type ) | |
494 | return 2; | |
495 | return rel_onoff( p->usbh, 1, index); | |
496 | } | |
497 | ||
498 | /** Turn ON all relay channels on the USB-Relay-Device | |
499 | @param hHandle -- which usb relay device your want to operate | |
500 | @returns: 0 -- success; 1 -- error | |
501 | */ | |
502 | int USBRL_API usb_relay_device_open_all_relay_channel(intptr_t hHandle) | |
503 | { | |
504 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)hHandle; | |
505 | if (!p) | |
506 | return 1; | |
507 | return rel_onoff( p->usbh, 1, -(int)p->urdi.type ); | |
508 | } | |
509 | ||
510 | /** Turn OFF a relay channel on the USB-Relay-Device | |
511 | @param index -- which channel your want to close | |
512 | @param hHandle -- which usb relay device your want to operate | |
513 | @returns: 0 -- success; 1 -- error; 2 -- index is outnumber the number of the usb relay device | |
514 | */ | |
515 | int USBRL_API usb_relay_device_close_one_relay_channel(intptr_t hHandle, int index) | |
516 | { | |
517 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)hHandle; | |
518 | if (!p) | |
519 | return 1; | |
520 | if ( index <= 0 || index > (int)p->urdi.type ) | |
521 | return 2; | |
522 | return rel_onoff( p->usbh, 0, index); | |
523 | } | |
524 | ||
525 | /** Turn OFF all relay channels on the USB-Relay-Device | |
526 | @param hHandle -- which usb relay device your want to operate | |
527 | @returns 0 -- success; 1 -- error | |
528 | */ | |
529 | int USBRL_API usb_relay_device_close_all_relay_channel(intptr_t hHandle) | |
530 | { | |
531 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)hHandle; | |
532 | if (!p) | |
533 | return 1; | |
534 | return rel_onoff( p->usbh, 0, -(int)p->urdi.type ); | |
535 | } | |
536 | ||
537 | /** Get status of all relays on the device | |
538 | Status bits: one bit indicate a relay status. | |
539 | bit 0/1/2/3/4/5/6/7/8 indicate channel 1/2/3/4/5/6/7/8 status | |
540 | 1 -- means ON, 0 -- means OFF. | |
541 | @returns: 0 -- success; 1 -- error | |
542 | */ | |
543 | int USBRL_API usb_relay_device_get_status(intptr_t hHandle, unsigned int *status) | |
544 | { | |
545 | struct usbrelay_internal_s *p = (struct usbrelay_internal_s *)hHandle; | |
546 | int err; | |
547 | if (!p) | |
548 | return 1; | |
549 | err = rel_read_status_raw(p->usbh, NULL); | |
550 | if ( err < 0 ) { | |
551 | printerr("Error reading data: %s\n", usbErrorMessage(err)); | |
5132ecf9 | 552 | return -err; |
c099d658 | 553 | } |
554 | ||
5132ecf9 | 555 | *status = (unsigned char)err; |
c099d658 | 556 | return 0; |
557 | } | |
558 | ||
63e45858 P |
559 | /************ Added ****************/ |
560 | ||
561 | /** Get the library (dll) version | |
562 | @return Lower 16 bits: the library version. Higher bits: undefined, ignore. | |
563 | @note The original DLL does not have this function! | |
c099d658 | 564 | */ |
565 | int USBRL_API usb_relay_device_lib_version(void) | |
566 | { | |
567 | return (int)(MY_VERSION); | |
568 | } | |
569 | ||
5132ecf9 | 570 | /** |
63e45858 P |
571 | The following functions are for non-native callers, to avoid fumbling with C structs. |
572 | Native C/C++ callers do not need to use these. | |
573 | The ptr_usb_relay_device_info arg is pointer to struct usb_relay_device_info, cast to intptr_t, void*, etc. | |
574 | */ | |
575 | ||
576 | /* Return next info struct pointer in the list returned by usb_relay_device_enumerate() */ | |
577 | intptr_t USBRL_API usb_relay_device_next_dev(intptr_t ptr_usb_relay_device_info) | |
578 | { | |
579 | if (!ptr_usb_relay_device_info) | |
580 | return 0; | |
581 | return (intptr_t)(void*)((pusb_relay_device_info_t)ptr_usb_relay_device_info)->next; | |
582 | } | |
583 | ||
584 | /* Get number of relay channels on the device */ | |
585 | int USBRL_API usb_relay_device_get_num_relays(intptr_t ptr_usb_relay_device_info) | |
586 | { | |
587 | if (!ptr_usb_relay_device_info) | |
588 | return 0; | |
589 | return (int)((pusb_relay_device_info_t)ptr_usb_relay_device_info)->type; | |
590 | } | |
591 | ||
592 | /* Get the ID string of the device. Returns pointer to const C string (1-byte, 0-terminated) */ | |
593 | intptr_t USBRL_API usb_relay_device_get_id_string(intptr_t ptr_usb_relay_device_info) | |
594 | { | |
595 | if (!ptr_usb_relay_device_info) | |
596 | return 0; | |
597 | return (intptr_t)(void const *)((pusb_relay_device_info_t)ptr_usb_relay_device_info)->serial_number; | |
598 | } | |
599 | ||
5132ecf9 P |
600 | /* Get status of all relays on the device. |
601 | * @return Bitmask of all relay channels state, if the value > 0. Negative values mean error. | |
602 | bit 0/1/2/3/4/5/6/7/8 indicate channel 1/2/3/4/5/6/7/8 status | |
603 | Each bit value 1 means ON, 0 means OFF. | |
604 | * @note This is same as usb_relay_device_get_status, but without dereferencing pointers. | |
605 | */ | |
606 | int USBRL_API usb_relay_device_get_status_bitmap(intptr_t hHandle) | |
607 | { | |
608 | unsigned int st; | |
609 | int err = usb_relay_device_get_status(hHandle, &st); | |
610 | if (0 == err) | |
611 | return (int)st; | |
612 | return (err > 0) ? (-err) : err; | |
c099d658 | 613 | } |
c099d658 | 614 | |
5132ecf9 P |
615 | #ifdef __cplusplus |
616 | } | |
617 | #endif |