1818 */
1919
2020#include <config.h>
21+
22+ #include <hidapi.h>
23+ #include <string.h>
24+
2125#include "protocol.h"
2226
27+ static const uint32_t scanopts [] = {
28+ SR_CONF_CONN ,
29+ };
30+
31+ static const uint32_t drvopts [] = {
32+ SR_CONF_MULTIPLEXER ,
33+ };
34+
35+ static const uint32_t devopts [] = {
36+ SR_CONF_CONN | SR_CONF_GET ,
37+ SR_CONF_ENABLED | SR_CONF_SET , /* Enable/disable all relays at once. */
38+ };
39+
40+ static const uint32_t devopts_cg [] = {
41+ SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET ,
42+ };
43+
2344static struct sr_dev_driver dcttech_usbrelay_driver_info ;
2445
46+ static struct sr_dev_inst * probe_device (const char * path , size_t relay_count )
47+ {
48+ hid_device * hid ;
49+ int ret ;
50+ char serno [SERNO_LENGTH + 1 ];
51+ uint8_t curr_state ;
52+ uint8_t report [1 + REPORT_BYTECOUNT ];
53+ GString * txt ;
54+ size_t snr_pos ;
55+ char c ;
56+ struct sr_dev_inst * sdi ;
57+ struct dev_context * devc ;
58+ struct channel_group_context * cgc ;
59+ size_t idx , nr ;
60+ struct sr_channel_group * cg ;
61+
62+ /* Open device, need to communicate to identify. */
63+ hid = hid_open_path (path );
64+ if (!hid )
65+ return NULL ;
66+
67+ /* Get an HID report. */
68+ hid_set_nonblocking (hid , 0 );
69+ memset (& report , 0 , sizeof (report ));
70+ report [0 ] = REPORT_NUMBER ;
71+ ret = hid_get_feature_report (hid , report , sizeof (report ));
72+ hid_close (hid );
73+ if (sr_log_loglevel_get () >= SR_LOG_SPEW ) {
74+ txt = sr_hexdump_new (report , sizeof (report ));
75+ sr_spew ("raw report, rc %d, bytes %s" , ret , txt -> str );
76+ sr_hexdump_free (txt );
77+ }
78+ if (ret != sizeof (report ))
79+ return NULL ;
80+
81+ /*
82+ * Serial number must be all printable characters. Relay state
83+ * is for information only, gets re-retrieved before configure
84+ * API calls (get/set).
85+ */
86+ memset (serno , 0 , sizeof (serno ));
87+ for (snr_pos = 0 ; snr_pos < SERNO_LENGTH ; snr_pos ++ ) {
88+ c = report [1 + snr_pos ];
89+ serno [snr_pos ] = c ;
90+ if (c < 0x20 || c > 0x7e )
91+ return NULL ;
92+ }
93+ curr_state = report [1 + STATE_INDEX ];
94+ sr_spew ("report data, serno[%s], relays 0x%02x." , serno , curr_state );
95+
96+ /*
97+ * Create a device instance, create channels (groups). The
98+ * caller fills in vendor, model, conn from USB enum details.
99+ */
100+ sdi = g_malloc0 (sizeof (* sdi ));
101+ devc = g_malloc0 (sizeof (* devc ));
102+ sdi -> priv = devc ;
103+ devc -> hid_path = g_strdup (path );
104+ devc -> relay_count = relay_count ;
105+ devc -> relay_mask = (1U << relay_count ) - 1 ;
106+ for (idx = 0 ; idx < devc -> relay_count ; idx ++ ) {
107+ nr = idx + 1 ;
108+ cg = g_malloc0 (sizeof (* cg ));
109+ cg -> name = g_strdup_printf ("R%zu" , nr );
110+ cgc = g_malloc0 (sizeof (* cgc ));
111+ cg -> priv = cgc ;
112+ cgc -> number = nr ;
113+ sdi -> channel_groups = g_slist_append (sdi -> channel_groups , cg );
114+ }
115+
116+ return sdi ;
117+ }
118+
25119static GSList * scan (struct sr_dev_driver * di , GSList * options )
26120{
27- struct drv_context * drvc ;
121+ const char * conn ;
28122 GSList * devices ;
29-
30- (void )options ;
123+ struct drv_context * drvc ;
124+ struct hid_device_info * devs , * curdev ;
125+ int ret ;
126+ wchar_t * ws ;
127+ char nonws [32 ];
128+ char * s , * endp ;
129+ unsigned long relay_count ;
130+ struct sr_dev_inst * sdi ;
131+
132+ /* Get optional conn= spec when provided. */
133+ conn = NULL ;
134+ (void )sr_serial_extract_options (options , & conn , NULL );
135+ if (conn && !* conn )
136+ conn = NULL ;
137+ /*
138+ * TODO Accept different types of conn= specs? Either paths that
139+ * hidapi(3) can open. Or bus.addr specs that we can check for
140+ * during USB enumeration. Derive want_path, want_bus, want_addr
141+ * here from the optional conn= spec.
142+ */
31143
32144 devices = NULL ;
33145 drvc = di -> context ;
34146 drvc -> instances = NULL ;
35147
36- /* TODO: scan for devices, either based on a SR_CONF_CONN option
37- * or on a USB scan. */
148+ /*
149+ * The firmware is V-USB based. The USB VID:PID identification
150+ * is shared across several projects. Need to inspect the vendor
151+ * and product _strings_ to actually identify the device.
152+ *
153+ * The USB serial number need not be present nor reliable. The
154+ * HID report contains a five character string which may serve
155+ * as an identification for boards (is said to differ between
156+ * boards). The last byte encodes the current relays state.
157+ */
158+ devs = hid_enumerate (VENDOR_ID , PRODUCT_ID );
159+ for (curdev = devs ; curdev ; curdev = curdev -> next ) {
160+ if (!curdev -> vendor_id || !curdev -> product_id )
161+ continue ;
162+ if (!curdev -> manufacturer_string || !curdev -> product_string )
163+ continue ;
164+ if (!* curdev -> manufacturer_string || !* curdev -> product_string )
165+ continue ;
166+ if (conn && strcmp (curdev -> path , conn ) != 0 ) {
167+ sr_dbg ("skipping %s, conn= mismatch" , curdev -> path );
168+ continue ;
169+ }
170+ sr_dbg ("checking %04hx:%04hx, vendor %ls, product %ls." ,
171+ curdev -> vendor_id , curdev -> product_id ,
172+ curdev -> manufacturer_string , curdev -> product_string );
173+
174+ /* Check USB details retrieved by enumeration. */
175+ ws = curdev -> manufacturer_string ;
176+ if (!ws || !wcslen (ws ))
177+ continue ;
178+ snprintf (nonws , sizeof (nonws ), "%ls" , ws );
179+ if (strcmp (nonws , VENDOR_STRING ) != 0 )
180+ continue ;
181+ ws = curdev -> product_string ;
182+ if (!ws || !wcslen (ws ))
183+ continue ;
184+ snprintf (nonws , sizeof (nonws ), "%ls" , ws );
185+ s = nonws ;
186+ if (!g_str_has_prefix (s , PRODUCT_STRING_PREFIX ))
187+ continue ;
188+ s += strlen (PRODUCT_STRING_PREFIX );
189+ ret = sr_atoul_base (s , & relay_count , & endp , 10 );
190+ if (ret != SR_OK || !endp || * endp )
191+ continue ;
192+ sr_info ("Found: HID path %s, relay count %lu." ,
193+ curdev -> path , relay_count );
194+
195+ /* Identify device by communicating to it. */
196+ sdi = probe_device (curdev -> path , relay_count );
197+ if (!sdi ) {
198+ sr_warn ("Failed to communicate to %s." , curdev -> path );
199+ continue ;
200+ }
201+
202+ /* Amend driver instance from USB enumeration details. */
203+ sdi -> vendor = g_strdup_printf ("%ls" , curdev -> manufacturer_string );
204+ sdi -> model = g_strdup_printf ("%ls" , curdev -> product_string );
205+ sdi -> conn = g_strdup (curdev -> path );
206+ sdi -> driver = & dcttech_usbrelay_driver_info ;
207+ sdi -> inst_type = SR_INST_USB ;
208+
209+ devices = g_slist_append (devices , sdi );
210+ }
211+ hid_free_enumeration (devs );
38212
39213 return devices ;
40214}
41215
42216static int dev_open (struct sr_dev_inst * sdi )
43217{
44- (void )sdi ;
218+ struct dev_context * devc ;
219+
220+ devc = sdi -> priv ;
221+
222+ if (devc -> hid_dev ) {
223+ hid_close (devc -> hid_dev );
224+ devc -> hid_dev = NULL ;
225+ }
45226
46- /* TODO: get handle from sdi->conn and open it. */
227+ devc -> hid_dev = hid_open_path (devc -> hid_path );
228+ if (!devc -> hid_dev )
229+ return SR_ERR_IO ;
230+
231+ (void )dcttech_usbrelay_update_state (sdi );
47232
48233 return SR_OK ;
49234}
50235
51236static int dev_close (struct sr_dev_inst * sdi )
52237{
53- (void )sdi ;
238+ struct dev_context * devc ;
239+
240+ devc = sdi -> priv ;
54241
55- /* TODO: get handle from sdi->conn and close it. */
242+ if (devc -> hid_dev ) {
243+ hid_close (devc -> hid_dev );
244+ devc -> hid_dev = NULL ;
245+ }
56246
57247 return SR_OK ;
58248}
59249
60250static int config_get (uint32_t key , GVariant * * data ,
61251 const struct sr_dev_inst * sdi , const struct sr_channel_group * cg )
62252{
253+ gboolean on ;
63254 int ret ;
64255
65- (void )sdi ;
66- (void )data ;
67- (void )cg ;
256+ if (!cg ) {
257+ switch (key ) {
258+ case SR_CONF_CONN :
259+ if (!sdi -> conn )
260+ return SR_ERR_NA ;
261+ * data = g_variant_new_string (sdi -> conn );
262+ return SR_OK ;
263+ default :
264+ return SR_ERR_NA ;
265+ }
266+ }
68267
69- ret = SR_OK ;
70268 switch (key ) {
71- /* TODO */
269+ case SR_CONF_ENABLED :
270+ ret = dcttech_usbrelay_query_cg (sdi , cg , & on );
271+ if (ret != SR_OK )
272+ return ret ;
273+ * data = g_variant_new_boolean (on );
274+ return SR_OK ;
72275 default :
73276 return SR_ERR_NA ;
74277 }
75-
76- return ret ;
77278}
78279
79280static int config_set (uint32_t key , GVariant * data ,
80281 const struct sr_dev_inst * sdi , const struct sr_channel_group * cg )
81282{
82- int ret ;
83-
84- (void )sdi ;
85- (void )data ;
86- (void )cg ;
87-
88- ret = SR_OK ;
89- switch (key ) {
90- /* TODO */
91- default :
92- ret = SR_ERR_NA ;
283+ gboolean on ;
284+
285+ if (!cg ) {
286+ switch (key ) {
287+ case SR_CONF_ENABLED :
288+ /* Enable/disable all channels at the same time. */
289+ on = g_variant_get_boolean (data );
290+ return dcttech_usbrelay_switch_cg (sdi , cg , on );
291+ default :
292+ return SR_ERR_NA ;
293+ }
294+ } else {
295+ switch (key ) {
296+ case SR_CONF_ENABLED :
297+ on = g_variant_get_boolean (data );
298+ return dcttech_usbrelay_switch_cg (sdi , cg , on );
299+ default :
300+ return SR_ERR_NA ;
301+ }
93302 }
94303
95- return ret ;
304+ return SR_OK ;
96305}
97306
98307static int config_list (uint32_t key , GVariant * * data ,
99308 const struct sr_dev_inst * sdi , const struct sr_channel_group * cg )
100309{
101- int ret ;
102310
103- (void )sdi ;
104- (void )data ;
105- (void )cg ;
311+ if (!cg ) {
312+ switch (key ) {
313+ case SR_CONF_SCAN_OPTIONS :
314+ case SR_CONF_DEVICE_OPTIONS :
315+ return STD_CONFIG_LIST (key , data , sdi , cg ,
316+ scanopts , drvopts , devopts );
317+ default :
318+ return SR_ERR_NA ;
319+ }
320+ }
106321
107- ret = SR_OK ;
108322 switch (key ) {
109- /* TODO */
323+ case SR_CONF_DEVICE_OPTIONS :
324+ * data = std_gvar_array_u32 (ARRAY_AND_SIZE (devopts_cg ));
325+ return SR_OK ;
110326 default :
111327 return SR_ERR_NA ;
112328 }
113-
114- return ret ;
115- }
116-
117- static int dev_acquisition_start (const struct sr_dev_inst * sdi )
118- {
119- /* TODO: configure hardware, reset acquisition state, set up
120- * callbacks and send header packet. */
121-
122- (void )sdi ;
123-
124- return SR_OK ;
125- }
126-
127- static int dev_acquisition_stop (struct sr_dev_inst * sdi )
128- {
129- /* TODO: stop acquisition. */
130-
131- (void )sdi ;
132-
133- return SR_OK ;
134329}
135330
136331static struct sr_dev_driver dcttech_usbrelay_driver_info = {
@@ -147,8 +342,8 @@ static struct sr_dev_driver dcttech_usbrelay_driver_info = {
147342 .config_list = config_list ,
148343 .dev_open = dev_open ,
149344 .dev_close = dev_close ,
150- .dev_acquisition_start = dev_acquisition_start ,
151- .dev_acquisition_stop = dev_acquisition_stop ,
345+ .dev_acquisition_start = std_dummy_dev_acquisition_start ,
346+ .dev_acquisition_stop = std_dummy_dev_acquisition_stop ,
152347 .context = NULL ,
153348};
154349SR_REGISTER_DEV_DRIVER (dcttech_usbrelay_driver_info );
0 commit comments