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