]> sigrok.org Git - libsigrok.git/blame - src/hardware/icstation-usbrelay/api.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / hardware / icstation-usbrelay / api.c
CommitLineData
dfa92ad4
FS
1/*
2 * This file is part of the libsigrok project.
3 *
cefdd911 4 * Copyright (C) 2021-2023 Frank Stettner <frank-stettner@gmx.net>
dfa92ad4
FS
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>
cefdd911 21
dfa92ad4
FS
22#include "protocol.h"
23
cefdd911 24#define SERIALCOMM "9600/8n1"
dfa92ad4 25
cefdd911
FS
26static const uint32_t scanopts[] = {
27 SR_CONF_CONN,
28 SR_CONF_SERIALCOMM,
29};
dfa92ad4 30
cefdd911
FS
31static const uint32_t drvopts[] = {
32 SR_CONF_MULTIPLEXER,
33};
dfa92ad4 34
cefdd911
FS
35static 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};
dfa92ad4 39
cefdd911
FS
40static const uint32_t devopts_cg[] = {
41 SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
42};
dfa92ad4 43
cefdd911
FS
44static const struct ics_usbrelay_profile supported_ics_usbrelay[] = {
45 { ICSE012A, 0xAB, "ICSE012A", 4 },
46 { ICSE013A, 0xAD, "ICSE013A", 2 },
47 { ICSE014A, 0xAC, "ICSE014A", 8 },
48};
dfa92ad4 49
cefdd911 50static GSList *scan(struct sr_dev_driver *di, GSList *options)
dfa92ad4 51{
cefdd911
FS
52 struct sr_dev_inst *sdi;
53 struct dev_context *devc;
54 struct sr_serial_dev_inst *serial;
55 GSList *devices;
56 size_t i, ch_idx;
57 const char *conn, *serialcomm;
58 int ret;
59 uint8_t device_id;
60 const struct ics_usbrelay_profile *profile;
61 struct sr_channel_group *cg;
62 struct channel_group_context *cgc;
dfa92ad4 63
cefdd911 64 devices = NULL;
dfa92ad4 65
cefdd911
FS
66 /* Only scan for a device when conn= was specified. */
67 conn = NULL;
68 serialcomm = SERIALCOMM;
69 if (sr_serial_extract_options(options, &conn, &serialcomm) != SR_OK)
70 return NULL;
71
72 serial = sr_serial_dev_inst_new(conn, serialcomm);
73 if (serial_open(serial, SERIAL_RDWR) != SR_OK)
74 return NULL;
75
76 /* Get device model. */
77 ret = icstation_usbrelay_identify(serial, &device_id);
78 if (ret != SR_OK) {
79 sr_err("Cannot retrieve identification details.");
80 serial_close(serial);
81 return NULL;
82 }
dfa92ad4 83
cefdd911
FS
84 for (i = 0; i < ARRAY_SIZE(supported_ics_usbrelay); i++) {
85 profile = &supported_ics_usbrelay[i];
86 if (device_id != profile->id)
87 continue;
88 sdi = g_malloc0(sizeof(*sdi));
89 sdi->status = SR_ST_INACTIVE;
90 sdi->vendor = g_strdup("ICStation");
91 sdi->model = g_strdup(profile->modelname);
92 sdi->inst_type = SR_INST_SERIAL;
93 sdi->conn = serial;
94 sdi->connection_id = g_strdup(conn);
95
96 devc = g_malloc0(sizeof(*devc));
97 sdi->priv = devc;
98 devc->relay_count = profile->nb_channels;
99 devc->relay_mask = (1U << devc->relay_count) - 1;
100 /* Assume that all relays are off at the start. */
101 devc->relay_state = 0;
102 for (ch_idx = 0; ch_idx < devc->relay_count; ch_idx++) {
103 cg = g_malloc0(sizeof(*cg));
104 cg->name = g_strdup_printf("R%zu", ch_idx + 1);
105 cgc = g_malloc0(sizeof(*cgc));
106 cg->priv = cgc;
107 cgc->index = ch_idx;
108 sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
109 }
110
111 devices = g_slist_append(devices, sdi);
112 break;
113 }
dfa92ad4 114
cefdd911
FS
115 serial_close(serial);
116 if (!devices) {
117 sr_serial_dev_inst_free(serial);
118 sr_warn("Unknown device identification 0x%02hhx.", device_id);
119 }
dfa92ad4 120
cefdd911 121 return std_scan_complete(di, devices);
dfa92ad4
FS
122}
123
124static int config_get(uint32_t key, GVariant **data,
125 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
126{
cefdd911
FS
127 struct dev_context *devc;
128 struct channel_group_context *cgc;
129 uint8_t mask;
130 gboolean on;
131
132 if (!sdi || !data)
133 return SR_ERR_ARG;
134 devc = sdi->priv;
135
136 if (!cg) {
137 switch (key) {
138 case SR_CONF_CONN:
139 *data = g_variant_new_string(sdi->connection_id);
140 break;
141 default:
142 return SR_ERR_NA;
143 }
144 }
dfa92ad4 145
dfa92ad4 146 switch (key) {
cefdd911
FS
147 case SR_CONF_ENABLED:
148 cgc = cg->priv;
149 mask = 1U << cgc->index;
150 on = devc->relay_state & mask;
151 *data = g_variant_new_boolean(on);
152 return SR_OK;
dfa92ad4
FS
153 default:
154 return SR_ERR_NA;
155 }
156
cefdd911 157 return SR_OK;
dfa92ad4
FS
158}
159
160static int config_set(uint32_t key, GVariant *data,
161 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
162{
cefdd911
FS
163 gboolean on;
164
165 if (!cg) {
166 switch (key) {
167 case SR_CONF_ENABLED:
168 /* Enable/disable all channels at the same time. */
169 on = g_variant_get_boolean(data);
170 return icstation_usbrelay_switch_cg(sdi, cg, on);
171 default:
172 return SR_ERR_NA;
173 }
174 } else {
175 switch (key) {
176 case SR_CONF_ENABLED:
177 on = g_variant_get_boolean(data);
178 return icstation_usbrelay_switch_cg(sdi, cg, on);
179 default:
180 return SR_ERR_NA;
181 }
dfa92ad4
FS
182 }
183
cefdd911 184 return SR_OK;
dfa92ad4
FS
185}
186
187static int config_list(uint32_t key, GVariant **data,
188 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
189{
cefdd911
FS
190 if (!cg) {
191 switch (key) {
192 case SR_CONF_SCAN_OPTIONS:
193 case SR_CONF_DEVICE_OPTIONS:
194 return STD_CONFIG_LIST(key, data, sdi, cg,
195 scanopts, drvopts, devopts);
196 default:
197 return SR_ERR_NA;
198 }
199 }
dfa92ad4 200
dfa92ad4 201 switch (key) {
cefdd911
FS
202 case SR_CONF_DEVICE_OPTIONS:
203 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
204 return SR_OK;
dfa92ad4
FS
205 default:
206 return SR_ERR_NA;
207 }
dfa92ad4
FS
208}
209
cefdd911 210static int dev_open(struct sr_dev_inst *sdi)
dfa92ad4 211{
cefdd911
FS
212 struct sr_serial_dev_inst *serial;
213 int ret;
dfa92ad4 214
cefdd911
FS
215 if (!sdi)
216 return SR_ERR_ARG;
217 serial = sdi->conn;
218 if (!serial)
219 return SR_ERR_ARG;
220
221 ret = std_serial_dev_open(sdi);
222 if (ret != SR_OK)
223 return ret;
224
225 /* Start command mode. */
226 ret = icstation_usbrelay_start(sdi);
227 if (ret != SR_OK) {
228 sr_err("Cannot initiate command mode.");
229 serial_close(serial);
230 return SR_ERR_IO;
231 }
dfa92ad4
FS
232
233 return SR_OK;
234}
235
236static struct sr_dev_driver icstation_usbrelay_driver_info = {
237 .name = "icstation-usbrelay",
cefdd911 238 .longname = "ICStation USBRelay",
dfa92ad4
FS
239 .api_version = 1,
240 .init = std_init,
241 .cleanup = std_cleanup,
242 .scan = scan,
243 .dev_list = std_dev_list,
244 .dev_clear = std_dev_clear,
245 .config_get = config_get,
246 .config_set = config_set,
247 .config_list = config_list,
248 .dev_open = dev_open,
cefdd911
FS
249 .dev_close = std_serial_dev_close,
250 .dev_acquisition_start = std_dummy_dev_acquisition_start,
251 .dev_acquisition_stop = std_dummy_dev_acquisition_stop,
dfa92ad4
FS
252 .context = NULL,
253};
254SR_REGISTER_DEV_DRIVER(icstation_usbrelay_driver_info);