]> sigrok.org Git - libsigrok.git/blame - src/hardware/devantech-eth008/api.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / hardware / devantech-eth008 / api.c
CommitLineData
c12ca361
GS
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2023 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
8712c783
GS
20#include "config.h"
21
22#include <string.h>
23
c12ca361
GS
24#include "protocol.h"
25
8712c783 26#define VENDOR_TEXT "Devantech"
c12ca361 27
8712c783
GS
28static const uint32_t scanopts[] = {
29 SR_CONF_CONN,
30};
31
32static const uint32_t drvopts[] = {
33 SR_CONF_MULTIPLEXER,
34};
c12ca361 35
8712c783
GS
36static const uint32_t devopts[] = {
37 SR_CONF_CONN | SR_CONF_GET,
38 SR_CONF_ENABLED | SR_CONF_SET, /* Enable/disable all relays at once. */
39};
c12ca361 40
8712c783
GS
41static const uint32_t devopts_cg_do[] = {
42 SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
43};
44
0220481e
GS
45static const uint32_t devopts_cg_di[] = {
46 SR_CONF_ENABLED | SR_CONF_GET,
47};
48
8712c783
GS
49static const uint32_t devopts_cg_ai[] = {
50 SR_CONF_VOLTAGE | SR_CONF_GET,
51};
52
c3fc22f2 53/* List of supported devices. Sorted by model ID. */
8712c783 54static const struct devantech_eth008_model models[] = {
c3fc22f2
GS
55 { 18, "ETH002", 2, 0, 0, 0, 1, 0, 0, },
56 { 19, "ETH008", 8, 0, 0, 0, 1, 0, 0, },
57 { 20, "ETH484", 16, 8, 4, 0, 2, 2, 0x00f0, },
58 { 21, "ETH8020", 20, 8, 8, 0, 3, 4, 0, },
59 { 22, "WIFI484", 16, 8, 4, 0, 2, 2, 0x00f0, },
60 { 24, "WIFI8020", 20, 8, 8, 0, 3, 4, 0, },
61 { 26, "WIFI002", 2, 0, 0, 0, 1, 0, 0, },
62 { 28, "WIFI008", 8, 0, 0, 0, 1, 0, 0, },
63 { 52, "ETH1610", 10, 16, 16, 0, 2, 2, 0, },
8712c783 64};
c12ca361 65
8712c783
GS
66static const struct devantech_eth008_model *find_model(uint8_t code)
67{
68 size_t idx;
69 const struct devantech_eth008_model *check;
70
71 for (idx = 0; idx < ARRAY_SIZE(models); idx++) {
72 check = &models[idx];
73 if (check->code != code)
74 continue;
75 return check;
76 }
c12ca361 77
8712c783 78 return NULL;
c12ca361
GS
79}
80
8712c783
GS
81static struct sr_dev_driver devantech_eth008_driver_info;
82
83static struct sr_dev_inst *probe_device_conn(const char *conn)
c12ca361 84{
8712c783
GS
85 struct sr_dev_inst *sdi;
86 struct dev_context *devc;
87 struct sr_serial_dev_inst *ser;
88 uint8_t code, hwver, fwver;
89 const struct devantech_eth008_model *model;
90 gboolean has_serno_cmd;
91 char snr_txt[16];
92 struct channel_group_context *cgc;
0220481e 93 size_t ch_idx, nr, do_idx, di_idx, ai_idx;
8712c783
GS
94 struct sr_channel_group *cg;
95 char cg_name[24];
96 int ret;
c12ca361 97
8712c783
GS
98 sdi = g_malloc0(sizeof(*sdi));
99 devc = g_malloc0(sizeof(*devc));
100 sdi->priv = devc;
101 ser = sr_serial_dev_inst_new(conn, NULL);
102 sdi->conn = ser;
103 if (!ser)
104 goto probe_fail;
105 ret = serial_open(ser, 0);
106 if (ret != SR_OK)
107 goto probe_fail;
108
109 ret = devantech_eth008_get_model(ser, &code, &hwver, &fwver);
110 if (ret != SR_OK)
111 goto probe_fail;
112 model = find_model(code);
113 if (!model) {
114 sr_err("Unknown model ID 0x%02x (HW %u, FW %u).",
115 code, hwver, fwver);
116 goto probe_fail;
117 }
118 devc->model_code = code;
119 devc->hardware_version = hwver;
120 devc->firmware_version = fwver;
121 devc->model = model;
122 sdi->vendor = g_strdup(VENDOR_TEXT);
123 sdi->model = g_strdup(model->name);
124 sdi->version = g_strdup_printf("HW%u FW%u", hwver, fwver);
125 sdi->connection_id = g_strdup(conn);
126 sdi->driver = &devantech_eth008_driver_info;
127 sdi->inst_type = SR_INST_SERIAL;
128
129 has_serno_cmd = TRUE;
130 if (model->min_serno_fw && fwver < model->min_serno_fw)
131 has_serno_cmd = FALSE;
132 if (has_serno_cmd) {
133 snr_txt[0] = '\0';
134 ret = devantech_eth008_get_serno(ser,
135 snr_txt, sizeof(snr_txt));
136 if (ret != SR_OK)
137 goto probe_fail;
138 sdi->serial_num = g_strdup(snr_txt);
139 }
c12ca361 140
8712c783
GS
141 ch_idx = 0;
142 devc->mask_do = (1UL << devc->model->ch_count_do) - 1;
0220481e 143 devc->mask_do &= ~devc->model->mask_do_missing;
8712c783
GS
144 for (do_idx = 0; do_idx < devc->model->ch_count_do; do_idx++) {
145 nr = do_idx + 1;
0220481e 146 if (devc->model->mask_do_missing & (1UL << do_idx))
6af128b6 147 continue;
8712c783
GS
148 snprintf(cg_name, sizeof(cg_name), "DO%zu", nr);
149 cgc = g_malloc0(sizeof(*cgc));
150 cg = sr_channel_group_new(sdi, cg_name, cgc);
151 cgc->index = do_idx;
152 cgc->number = nr;
153 cgc->ch_type = DV_CH_DIGITAL_OUTPUT;
154 (void)cg;
155 ch_idx++;
156 }
0220481e
GS
157 for (di_idx = 0; di_idx < devc->model->ch_count_di; di_idx++) {
158 nr = di_idx + 1;
159 snprintf(cg_name, sizeof(cg_name), "DI%zu", nr);
160 cgc = g_malloc0(sizeof(*cgc));
161 cg = sr_channel_group_new(sdi, cg_name, cgc);
162 cgc->index = di_idx;
163 cgc->number = nr;
164 cgc->ch_type = DV_CH_DIGITAL_INPUT;
165 (void)cg;
166 ch_idx++;
167 }
168 for (ai_idx = 0; ai_idx < devc->model->ch_count_ai; ai_idx++) {
169 nr = ai_idx + 1;
170 snprintf(cg_name, sizeof(cg_name), "AI%zu", nr);
171 cgc = g_malloc0(sizeof(*cgc));
172 cg = sr_channel_group_new(sdi, cg_name, cgc);
173 cgc->index = ai_idx;
174 cgc->number = nr;
175 cgc->ch_type = DV_CH_ANALOG_INPUT;
176 (void)cg;
177 ch_idx++;
178 }
8712c783
GS
179 if (1) {
180 /* Create an analog channel for the supply voltage. */
181 snprintf(cg_name, sizeof(cg_name), "Vsupply");
182 cgc = g_malloc0(sizeof(*cgc));
183 cg = sr_channel_group_new(sdi, cg_name, cgc);
184 cgc->index = 0;
185 cgc->number = 0;
186 cgc->ch_type = DV_CH_SUPPLY_VOLTAGE;
187 (void)cg;
188 ch_idx++;
189 }
190
191 return sdi;
192
193probe_fail:
194 if (ser) {
195 serial_close(ser);
196 sr_serial_dev_inst_free(ser);
197 }
198 if (devc) {
199 g_free(devc);
200 }
201 if (sdi) {
202 sdi->priv = NULL;
203 sr_dev_inst_free(sdi);
204 sdi = NULL;
205 }
206 return sdi;
c12ca361
GS
207}
208
8712c783 209static GSList *scan(struct sr_dev_driver *di, GSList *options)
c12ca361 210{
8712c783
GS
211 struct drv_context *drvc;
212 const char *conn;
213 GSList *devices;
214 struct sr_dev_inst *sdi;
c12ca361 215
8712c783
GS
216 drvc = di->context;
217 drvc->instances = NULL;
c12ca361 218
8712c783
GS
219 /* A conn= spec is required for the TCP attached device. */
220 conn = NULL;
221 (void)sr_serial_extract_options(options, &conn, NULL);
222 if (!conn || !*conn)
223 return NULL;
224
225 devices = NULL;
226 sdi = probe_device_conn(conn);
227 if (sdi)
228 devices = g_slist_append(devices, sdi);
229
230 return std_scan_complete(di, devices);
c12ca361
GS
231}
232
233static int config_get(uint32_t key, GVariant **data,
234 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
235{
8712c783
GS
236 struct channel_group_context *cgc;
237 gboolean on;
238 uint16_t vin;
239 double vsupply;
c12ca361
GS
240 int ret;
241
8712c783
GS
242 if (!cg) {
243 switch (key) {
244 case SR_CONF_CONN:
245 if (!sdi->connection_id)
246 return SR_ERR_NA;
247 *data = g_variant_new_string(sdi->connection_id);
248 return SR_OK;
249 default:
250 return SR_ERR_NA;
251 }
252 }
c12ca361 253
8712c783
GS
254 cgc = cg->priv;
255 if (!cgc)
256 return SR_ERR_NA;
c12ca361 257 switch (key) {
8712c783
GS
258 case SR_CONF_ENABLED:
259 if (cgc->ch_type == DV_CH_DIGITAL_OUTPUT) {
260 ret = devantech_eth008_query_do(sdi, cg, &on);
261 if (ret != SR_OK)
262 return ret;
263 *data = g_variant_new_boolean(on);
264 return SR_OK;
265 }
0220481e
GS
266 if (cgc->ch_type == DV_CH_DIGITAL_INPUT) {
267 ret = devantech_eth008_query_di(sdi, cg, &on);
268 if (ret != SR_OK)
269 return ret;
270 *data = g_variant_new_boolean(on);
271 return SR_OK;
272 }
8712c783
GS
273 return SR_ERR_NA;
274 case SR_CONF_VOLTAGE:
0220481e
GS
275 if (cgc->ch_type == DV_CH_ANALOG_INPUT) {
276 ret = devantech_eth008_query_ai(sdi, cg, &vin);
277 if (ret != SR_OK)
278 return ret;
279 *data = g_variant_new_uint32(vin);
280 return SR_OK;
281 }
8712c783
GS
282 if (cgc->ch_type == DV_CH_SUPPLY_VOLTAGE) {
283 ret = devantech_eth008_query_supply(sdi, cg, &vin);
284 if (ret != SR_OK)
285 return ret;
286 vsupply = vin;
287 vsupply /= 1000.;
288 *data = g_variant_new_double(vsupply);
289 return SR_OK;
290 }
291 return SR_ERR_NA;
c12ca361
GS
292 default:
293 return SR_ERR_NA;
294 }
c12ca361
GS
295}
296
297static int config_set(uint32_t key, GVariant *data,
298 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
299{
8712c783
GS
300 struct channel_group_context *cgc;
301 gboolean on;
302
303 if (!cg) {
304 switch (key) {
305 case SR_CONF_ENABLED:
306 /* Enable/disable all channels at the same time. */
307 on = g_variant_get_boolean(data);
308 return devantech_eth008_setup_do(sdi, cg, on);
309 default:
310 return SR_ERR_NA;
311 }
312 }
c12ca361 313
8712c783
GS
314 cgc = cg->priv;
315 if (!cgc)
316 return SR_ERR_NA;
c12ca361 317 switch (key) {
8712c783
GS
318 case SR_CONF_ENABLED:
319 if (cgc->ch_type != DV_CH_DIGITAL_OUTPUT)
320 return SR_ERR_NA;
321 on = g_variant_get_boolean(data);
322 return devantech_eth008_setup_do(sdi, cg, on);
c12ca361 323 default:
8712c783 324 return SR_ERR_NA;
c12ca361 325 }
c12ca361
GS
326}
327
328static int config_list(uint32_t key, GVariant **data,
329 const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
330{
8712c783
GS
331 struct channel_group_context *cgc;
332
333 if (!cg) {
334 switch (key) {
335 case SR_CONF_SCAN_OPTIONS:
336 case SR_CONF_DEVICE_OPTIONS:
337 return STD_CONFIG_LIST(key, data, sdi, cg,
338 scanopts, drvopts, devopts);
339 default:
340 return SR_ERR_NA;
341 }
342 }
c12ca361 343
8712c783
GS
344 cgc = cg->priv;
345 if (!cgc)
346 return SR_ERR_NA;
c12ca361 347 switch (key) {
8712c783
GS
348 case SR_CONF_DEVICE_OPTIONS:
349 if (cgc->ch_type == DV_CH_DIGITAL_OUTPUT) {
350 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_do));
351 return SR_OK;
352 }
0220481e
GS
353 if (cgc->ch_type == DV_CH_DIGITAL_INPUT) {
354 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_di));
355 return SR_OK;
356 }
357 if (cgc->ch_type == DV_CH_ANALOG_INPUT) {
358 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_ai));
359 return SR_OK;
360 }
8712c783
GS
361 if (cgc->ch_type == DV_CH_SUPPLY_VOLTAGE) {
362 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg_ai));
363 return SR_OK;
364 }
365 return SR_ERR_NA;
c12ca361
GS
366 default:
367 return SR_ERR_NA;
368 }
c12ca361
GS
369}
370
371static struct sr_dev_driver devantech_eth008_driver_info = {
372 .name = "devantech-eth008",
373 .longname = "Devantech ETH008",
374 .api_version = 1,
375 .init = std_init,
376 .cleanup = std_cleanup,
377 .scan = scan,
378 .dev_list = std_dev_list,
379 .dev_clear = std_dev_clear,
380 .config_get = config_get,
381 .config_set = config_set,
382 .config_list = config_list,
8712c783
GS
383 .dev_open = std_serial_dev_open,
384 .dev_close = std_serial_dev_close,
385 .dev_acquisition_start = std_dummy_dev_acquisition_start,
386 .dev_acquisition_stop = std_dummy_dev_acquisition_stop,
c12ca361
GS
387 .context = NULL,
388};
389SR_REGISTER_DEV_DRIVER(devantech_eth008_driver_info);