f90b9c065e0361b522f7897b1a30db6195d5d7a8
[usb-relay-hid.git] / commandline / usbrelay-cmd.c
1 // Chinese USB/HID relay command line tool:
2 //
3 // pa01 15-Apr-2014
4 // Currently finds the 1st matching device by ven,dev, product name string.
5 // Two channel devices only!
6 // TODO:
7 // - Enum all matching devices, select one by ID
8 // - Determine the relay model (1 or 2 or more) by product string?
9 // Build for Windows: using VC++ 2008 and WDK7.1
10 //~~~~~~~~~~~~~~~~~~~~~~~~
11
12 /* Prototype: V-USB example: vusb-20121206/examples/hid-data/commandline/hidtool.c
13 * Author: Christian Starkjohann
14 * Creation Date: 2008-04-11
15 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
16 */
17
18 #define A_VER_STR "r0.2 (2 ch. only)"
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include "hidusb-tool.h"
24
25 #define USB_CFG_VENDOR_NAME "www.dcttech.com"
26 #define USB_CFG_DEVICE_NAME "USBRelay2" // can be relay1... relay8?
27
28
29 static int g_max_relay_num = 0;
30
31 static int rel_read_status(USBDEVHANDLE dev, void *raw_data);
32
33 /* ------------------------------------------------------------------------- */
34
35 static const char *usbErrorMessage(int errCode)
36 {
37 static char buffer[80];
38
39 switch(errCode){
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";
43 default:
44 snprintf(buffer, sizeof(buffer), "Unknown USB error %d", errCode);
45 return buffer;
46 }
47 return NULL; /* not reached */
48 }
49
50 static USBDEVHANDLE openDevice(void)
51 {
52 USBDEVHANDLE dev = 0;
53 char vendorName[] = USB_CFG_VENDOR_NAME,
54 productName[] = USB_CFG_DEVICE_NAME;
55 int vid = USB_CFG_VENDOR_ID;
56 int pid = USB_CFG_DEVICE_ID;
57 int err;
58
59 // TODO: enumerate all instances, then filter by unique ID
60 if((err = usbhidOpenDevice(&dev, vid, vendorName, pid, productName, 0)) != 0){
61 fprintf(stderr, "error finding %s: %s\n", productName, usbErrorMessage(err));
62 return NULL;
63 }
64
65 { /* Check the unique ID: 5 bytes at offs 0 */
66 char buffer[16];
67 err = rel_read_status(dev, buffer);
68 if( err < 0 ){
69 fprintf(stderr, "error reading report 0: %s\n", usbErrorMessage(err));
70 usbhidCloseDevice(dev);
71 return NULL;
72 }else{
73 int i;
74 //hexdump(buffer + 1, sizeof(buffer) - 1);
75 for (i=1; i <=5; i++) {
76 unsigned char x = (unsigned char)buffer[i];
77 if (x <= 0x20 || x >= 0x7F) {
78 fprintf(stderr, "Bad device ID!\n");
79 usbhidCloseDevice(dev);
80 return NULL;
81 }
82 }
83 if( buffer[6] != 0 ) {
84 fprintf(stderr, "Bad device ID!\n");
85 usbhidCloseDevice(dev);
86 return NULL;
87 }
88
89 DEBUG_PRINT(("Device %s found: ID=[%5s]\n", USB_CFG_DEVICE_NAME, &buffer[1]));
90 g_max_relay_num = 2; /* hardcoded for "USBRelay2" */
91 }
92 }
93
94 return dev;
95 }
96
97 /* ------------------------------------------------------------------------- */
98 #if 0
99 static void hexdump(char *buffer, int len)
100 {
101 int i;
102 FILE *fp = stdout;
103
104 for(i = 0; i < len; i++){
105 if(i != 0){
106 if(i % 16 == 0){
107 fprintf(fp, "\n");
108 }else{
109 fprintf(fp, " ");
110 }
111 }
112 fprintf(fp, "0x%02x", buffer[i] & 0xff);
113 }
114 if(i != 0)
115 fprintf(fp, "\n");
116 }
117 #endif
118
119 /* ------------------------------------------------------------------------- */
120
121 static void usage(char *myName)
122 {
123 char *p = strrchr(myName, '\\'); /* windows */
124 if (p) myName = p + 1;
125 p = strrchr(myName, '/'); /* whatever */
126 if (p) myName = p + 1;
127
128 fprintf(stderr, "USBHID relay utility, " A_VER_STR "\n");
129 fprintf(stderr, "Usage:\n");
130 fprintf(stderr, " %s on <num> - turn relay <num> ON\n", myName);
131 fprintf(stderr, " %s off <num> - turn relay <num> OFF\n", myName);
132 fprintf(stderr, " %s state - print state of the relays\n", myName);
133 }
134
135
136 // Read state of all relays
137 // @return bit mask of all relays (R1->bit 0, R2->bit 1 ...) or -1 on error
138 static int rel_read_status(USBDEVHANDLE dev, void *raw_data)
139 {
140 char buffer[10];
141 int err;
142 int reportnum = 0;
143 int len = 8 + 1; /* report id 1 byte + 8 bytes data */
144 memset(buffer, 0, sizeof(buffer));
145
146 err = usbhidGetReport(dev, reportnum, buffer, &len);
147 if ( err ) {
148 fprintf(stderr, "error reading status: %s\n", usbErrorMessage(err));
149 return -1;
150 }
151
152 if ( len != 9 || buffer[0] != reportnum ) {
153 fprintf(stderr, "ERROR: wrong HID report returned!\n", len);
154 return -2;
155 }
156
157 if (raw_data) {
158 /* REVISE! copy raw report data */
159 memcpy( raw_data, buffer, sizeof(buffer) );
160 }
161
162 return (int)(unsigned char)buffer[8]; /* byte of relay states */
163 }
164
165
166 static int rel_onoff( USBDEVHANDLE dev, int is_on, char const *numstr )
167 {
168 unsigned char buffer[10];
169 int err = -1;
170 int relaynum = numstr ? atoi(numstr) : 0;
171
172 if ( numstr && (0 == strcmp(numstr,"*")) ) {
173 char x[2] = {'1', 0};
174 int i;
175 for (i = 1; i <= g_max_relay_num; i++) {
176 x[0] = (char)('0' + i);
177 err = rel_onoff(dev, is_on, x);
178 if (err) break;
179 }
180 return err;
181 }
182
183 if ( relaynum <= 0 || relaynum > g_max_relay_num ) {
184 fprintf(stderr, "Invalid relay number. Must be 1-%d or * (all)\n", g_max_relay_num);
185 return 1;
186 }
187
188 memset(buffer, 0, sizeof(buffer));
189 buffer[0] = 0; /* report # */
190 buffer[1] = is_on ? 0xFF : 0xFD;
191 buffer[2] = (unsigned char)relaynum;
192 if((err = usbhidSetReport(dev, buffer, 9)) != 0) {
193 fprintf(stderr, "Error writing data: %s\n", usbErrorMessage(err));
194 return 1;
195 }
196
197 // Read back & verify
198 err = rel_read_status(dev, NULL);
199 if ( err >= 0 ) {
200 err = (err >> (unsigned)(relaynum -1)) & 1;
201 err ^= !!is_on;
202 }
203
204 if ( err ) {
205 fprintf(stderr, "Error: failed set %s relay %u\n", is_on ? "ON":"OFF", relaynum);
206 return 1;
207 }
208
209 return 0;
210 }
211
212
213 int main(int argc, char **argv)
214 {
215 USBDEVHANDLE dev;
216 int err;
217 char const *arg1 = (argc >= 2) ? argv[1] : NULL;
218 char const *arg2 = (argc >= 3) ? argv[2] : NULL;
219
220 if ( !arg1 ) {
221 usage(argv[0]);
222 exit(1);
223 }
224
225 dev = openDevice();
226 if ( !dev )
227 exit(1);
228
229 // if ( strcasecmp(arg1, "state") == 0 ){
230 if ( strncasecmp(arg1, "stat", 4) == 0 ){
231 char buffer[10];
232 err = rel_read_status(dev, buffer);
233 if ( err < 0 ){
234 fprintf(stderr, "error reading data: %s\n", usbErrorMessage(err));
235 err = 1;
236 } else {
237 //hexdump(buffer + 1, len - 1);
238 printf("State: R1=%d R2=%d Board ID=[%5.5s]\n", !!(err & 0x1), !!(err & 0x2), &buffer[1] );
239 }
240 }else if( strcasecmp(arg1, "on" ) == 0){
241 err = rel_onoff(dev, 1, arg2);
242 }else if( strcasecmp(arg1, "off" ) == 0){
243 err = rel_onoff(dev, 0, arg2);
244 }else {
245 usage(argv[0]);
246 err = 2;
247 }
248
249 if ( dev ) {
250 usbhidCloseDevice(dev);
251 }
252
253 return err;
254 }
255
256 /* ------------------------------------------------------------------------- */