]> sigrok.org Git - libsigrok.git/blame - src/hardware/dcttech-usbrelay/protocol.c
dcttech-usbrelay: implement multiplexer driver for USB relay card
[libsigrok.git] / src / hardware / dcttech-usbrelay / protocol.c
CommitLineData
64d54a71
GS
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2021 Gerhard Sittig <gerhard.sittig@gmx.net>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <config.h>
321f85fb
GS
21
22#include <string.h>
23
64d54a71
GS
24#include "protocol.h"
25
321f85fb 26SR_PRIV int dcttech_usbrelay_update_state(const struct sr_dev_inst *sdi)
64d54a71 27{
64d54a71 28 struct dev_context *devc;
321f85fb
GS
29 uint8_t report[1 + REPORT_BYTECOUNT];
30 int ret;
31 GString *txt;
32
33 devc = sdi->priv;
34
35 /* Get another HID report. */
36 memset(report, 0, sizeof(report));
37 report[0] = REPORT_NUMBER;
38 ret = hid_get_feature_report(devc->hid_dev, report, sizeof(report));
39 if (ret != sizeof(report))
40 return SR_ERR_IO;
41 if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
42 txt = sr_hexdump_new(report, sizeof(report));
43 sr_spew("got report bytes: %s", txt->str);
44 sr_hexdump_free(txt);
45 }
64d54a71 46
321f85fb
GS
47 /* Update relay state cache from HID report content. */
48 devc->relay_state = report[1 + STATE_INDEX];
49 devc->relay_state &= devc->relay_mask;
50
51 return SR_OK;
52}
53
54SR_PRIV int dcttech_usbrelay_switch_cg(const struct sr_dev_inst *sdi,
55 const struct sr_channel_group *cg, gboolean on)
56{
57 struct dev_context *devc;
58 struct channel_group_context *cgc;
59 gboolean is_all;
60 size_t relay_idx;
61 uint8_t report[1 + REPORT_BYTECOUNT];
62 int ret;
63 GString *txt;
64d54a71 64
321f85fb 65 devc = sdi->priv;
64d54a71 66
321f85fb
GS
67 /* Determine if all or a single relay should be turned off or on. */
68 is_all = !cg ? TRUE : FALSE;
69 if (is_all) {
70 relay_idx = 0;
71 } else {
72 cgc = cg->priv;
73 relay_idx = cgc->number;
74 }
64d54a71 75
321f85fb
GS
76 /*
77 * Construct and send the HID report. Notice the weird(?) bit
78 * pattern. Bit 1 is low when all relays are affected at once,
79 * and high to control an individual relay? Bit 0 communicates
80 * whether the relay(s) should be on or off? And all other bits
81 * are always set? It's assumed that the explicit assignment of
82 * full byte values simplifies future maintenance.
83 */
84 memset(report, 0, sizeof(report));
85 report[0] = REPORT_NUMBER;
86 if (is_all) {
87 if (on) {
88 report[1] = 0xfe;
89 } else {
90 report[1] = 0xfc;
91 }
92 } else {
93 if (on) {
94 report[1] = 0xff;
95 report[2] = relay_idx;
96 } else {
97 report[1] = 0xfd;
98 report[2] = relay_idx;
99 }
100 }
101 if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
102 txt = sr_hexdump_new(report, sizeof(report));
103 sr_spew("sending report bytes: %s", txt->str);
104 sr_hexdump_free(txt);
64d54a71 105 }
321f85fb
GS
106 ret = hid_send_feature_report(devc->hid_dev, report, sizeof(report));
107 if (ret != sizeof(report))
108 return SR_ERR_IO;
109
110 /* Update relay state cache (non-fatal). */
111 (void)dcttech_usbrelay_update_state(sdi);
112
113 return SR_OK;
114}
115
116/* Answers the query from cached relay state. Beware of 1-based indexing. */
117SR_PRIV int dcttech_usbrelay_query_cg(const struct sr_dev_inst *sdi,
118 const struct sr_channel_group *cg, gboolean *on)
119{
120 struct dev_context *devc;
121 struct channel_group_context *cgc;
122 size_t relay_idx;
123 uint32_t relay_mask;
124
125 devc = sdi->priv;
126 if (!cg)
127 return SR_ERR_ARG;
128 cgc = cg->priv;
129 relay_idx = cgc->number;
130 if (relay_idx < 1 || relay_idx > devc->relay_count)
131 return SR_ERR_ARG;
132 relay_mask = 1U << (relay_idx - 1);
133
134 *on = devc->relay_state & relay_mask;
64d54a71 135
321f85fb 136 return SR_OK;
64d54a71 137}