1 // Chinese USB/HID relay command line tool:
3 // pa02 19-Nov-2014 supports 1,2,4 - relay devices
4 // Currently finds the 1st matching device by ven,dev, product name string.
6 // - Support multiple devices, select one by ID!
7 // Build for Windows: using VC++ 2008 and WDK7.1
8 //~~~~~~~~~~~~~~~~~~~~~~~~
10 /* Prototype: V-USB example: vusb-20121206/examples/hid-data/commandline/hidtool.c
11 * Author: Christian Starkjohann
12 * Creation Date: 2008-04-11
13 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
16 #define A_VER_STR "r1.1x (1 device only)"
21 #include "hidusb-tool.h"
23 #define USB_RELAY_VENDOR_NAME "www.dcttech.com"
24 #define USB_RELAY1_NAME "USBRelay1" // 1 relay
25 #define USB_RELAY2_NAME "USBRelay2" // 2 relays
26 #define USB_RELAY4_NAME "USBRelay4" // 4 relays
29 static int g_max_relay_num
= 0;
31 static int rel_read_status_raw(USBDEVHANDLE dev
, void *raw_data
);
33 /* ------------------------------------------------------------------------- */
35 static const char *usbErrorMessage(int errCode
)
37 static char buffer
[80];
40 case USBOPEN_ERR_ACCESS
: return "Access to device denied";
41 case USBOPEN_ERR_NOTFOUND
: return "The specified device was not found";
42 case USBOPEN_ERR_IO
: return "Communication error with device";
45 snprintf(buffer
, sizeof(buffer
), "Unknown USB error %d", errCode
);
49 static USBDEVHANDLE
openDevice(void)
52 char vendorName
[] = USB_RELAY_VENDOR_NAME
,
53 productName
[] = USB_RELAY1_NAME
;
54 int vid
= USB_CFG_VENDOR_ID
;
55 int pid
= USB_CFG_DEVICE_ID
;
59 // TODO: enumerate all instances, then filter by unique ID
60 //$$$ find any one device
61 strcpy(productName
, USB_RELAY2_NAME
);
62 if((err
= usbhidOpenDevice(&dev
, vid
, vendorName
, pid
, productName
, 0)) == 0) {
67 strcpy(productName
, USB_RELAY1_NAME
);
68 if((err
= usbhidOpenDevice(&dev
, vid
, vendorName
, pid
, productName
, 0)) == 0) {
73 strcpy(productName
, USB_RELAY4_NAME
);
74 if((err
= usbhidOpenDevice(&dev
, vid
, vendorName
, pid
, productName
, 0)) == 0) {
79 fprintf(stderr
, "error finding USB relay: %s\n", usbErrorMessage(err
));
83 { /* Check the unique ID: 5 bytes at offs 0 */
85 err
= rel_read_status_raw(dev
, buffer
);
87 fprintf(stderr
, "error reading report 0: %s\n", usbErrorMessage(err
));
88 usbhidCloseDevice(dev
);
92 //hexdump(buffer + 1, sizeof(buffer) - 1);
93 for (i
=1; i
<=5; i
++) {
94 unsigned char x
= (unsigned char)buffer
[i
];
95 if (x
<= 0x20 || x
>= 0x7F) {
96 fprintf(stderr
, "Bad device ID!\n");
97 usbhidCloseDevice(dev
);
101 if( buffer
[6] != 0 ) {
102 fprintf(stderr
, "Bad device ID!\n");
103 usbhidCloseDevice(dev
);
107 DEBUG_PRINT(("Device %s found: ID=[%5s]\n", USB_CFG_DEVICE_NAME
, &buffer
[1]));
108 g_max_relay_num
= num
;
115 /* ------------------------------------------------------------------------- */
117 static void hexdump(char *buffer
, int len
)
122 for(i
= 0; i
< len
; i
++){
130 fprintf(fp
, "0x%02x", buffer
[i
] & 0xff);
137 /* ------------------------------------------------------------------------- */
139 static void usage(char *myName
)
141 char *p
= strrchr(myName
, '\\'); /* windows */
142 if (p
) myName
= p
+ 1;
143 else p
= strrchr(myName
, '/'); /* whatever */
144 if (p
) myName
= p
+ 1;
146 fprintf(stderr
, "USBHID relay utility, " A_VER_STR
"\n");
147 fprintf(stderr
, "Usage:\n");
148 fprintf(stderr
, " %s on <num> - turn relay <num> ON\n", myName
);
149 fprintf(stderr
, " %s off <num> - turn relay <num> OFF\n", myName
);
150 fprintf(stderr
, " %s state - print state of the relays\n", myName
);
154 // Read state of all relays
155 // @return bit mask of all relays (R1->bit 0, R2->bit 1 ...) or -1 on error
156 static int rel_read_status_raw(USBDEVHANDLE dev
, void *raw_data
)
161 int len
= 8 + 1; /* report id 1 byte + 8 bytes data */
162 memset(buffer
, 0, sizeof(buffer
));
164 err
= usbhidGetReport(dev
, reportnum
, buffer
, &len
);
166 fprintf(stderr
, "error reading status: %s\n", usbErrorMessage(err
));
170 if ( len
!= 9 || buffer
[0] != reportnum
) {
171 fprintf(stderr
, "ERROR: wrong HID report returned!\n", len
);
176 /* copy raw report data */
177 memcpy( raw_data
, buffer
, sizeof(buffer
) );
180 return (int)(unsigned char)buffer
[8]; /* byte of relay states */
184 static int rel_onoff( USBDEVHANDLE dev
, int is_on
, char const *numstr
)
186 unsigned char buffer
[10];
188 int relaynum
= numstr
? atoi(numstr
) : 0;
190 if ( numstr
&& (0 == strcmp(numstr
,"*")) ) {
191 char x
[2] = {'1', 0};
193 for (i
= 1; i
<= g_max_relay_num
; i
++) {
194 x
[0] = (char)('0' + i
);
195 err
= rel_onoff(dev
, is_on
, x
);
201 if ( relaynum
<= 0 || relaynum
> g_max_relay_num
) {
202 fprintf(stderr
, "Invalid relay number. Must be 1-%d or * (all)\n", g_max_relay_num
);
206 memset(buffer
, 0, sizeof(buffer
));
207 buffer
[0] = 0; /* report # */
208 buffer
[1] = is_on
? 0xFF : 0xFD;
209 buffer
[2] = (unsigned char)relaynum
;
210 if((err
= usbhidSetReport(dev
, buffer
, 9)) != 0) {
211 fprintf(stderr
, "Error writing data: %s\n", usbErrorMessage(err
));
215 // Read back & verify
216 err
= rel_read_status_raw(dev
, NULL
);
218 err
= (err
>> (unsigned)(relaynum
-1)) & 1;
223 fprintf(stderr
, "Error: failed set %s relay %u\n", is_on
? "ON":"OFF", relaynum
);
231 static int show_status(USBDEVHANDLE dev
)
235 static const char* on_off
[] = {"OFF","ON"};
237 #define onoff(n) on_off[!!(err & (1U << n))]
239 err
= rel_read_status_raw(dev
, buffer
);
241 fprintf(stderr
, "error reading data: %s\n", usbErrorMessage(err
));
244 //hexdump(buffer + 1, len - 1);
245 switch (g_max_relay_num
) {
247 printf("Board ID=[%5.5s] State: R1=%s\n", &buffer
[1], onoff(0) );
250 printf("Board ID=[%5.5s] State: R1=%s R2=%s\n",
251 &buffer
[1], onoff(0), onoff(1) );
254 printf("Board ID=[%5.5s] State: R1=%s R3=%s R1=%s R4=%s\n",
255 &buffer
[1], onoff(0), onoff(1), onoff(2), onoff(3) );
258 printf("Board ID=[%5.5s] State: %2.2X (hex)\n", &buffer
[1], (unsigned char)err
);
267 int main(int argc
, char **argv
)
269 USBDEVHANDLE dev
= 0;
271 char const *arg1
= (argc
>= 2) ? argv
[1] : NULL
;
272 char const *arg2
= (argc
>= 3) ? argv
[2] : NULL
;
283 if ( strncasecmp(arg1
, "stat", 4) == 0 ) { // stat|state|status
284 err
= show_status(dev
);
285 // TODO enumerate all devices
286 }else if( strcasecmp(arg1
, "on" ) == 0) {
287 err
= rel_onoff(dev
, 1, arg2
);
288 }else if( strcasecmp(arg1
, "off" ) == 0) {
289 err
= rel_onoff(dev
, 0, arg2
);
296 usbhidCloseDevice(dev
);
302 /* ------------------------------------------------------------------------- */