]> sigrok.org Git - libsigrok.git/blob - src/hardware/devantech-eth008/api.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / hardware / devantech-eth008 / api.c
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
20 #include "config.h"
21
22 #include <string.h>
23
24 #include "protocol.h"
25
26 #define VENDOR_TEXT     "Devantech"
27
28 static const uint32_t scanopts[] = {
29         SR_CONF_CONN,
30 };
31
32 static const uint32_t drvopts[] = {
33         SR_CONF_MULTIPLEXER,
34 };
35
36 static 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 };
40
41 static const uint32_t devopts_cg_do[] = {
42         SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
43 };
44
45 static const uint32_t devopts_cg_di[] = {
46         SR_CONF_ENABLED | SR_CONF_GET,
47 };
48
49 static const uint32_t devopts_cg_ai[] = {
50         SR_CONF_VOLTAGE | SR_CONF_GET,
51 };
52
53 /* List of supported devices. Sorted by model ID. */
54 static const struct devantech_eth008_model models[] = {
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, },
64 };
65
66 static 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         }
77
78         return NULL;
79 }
80
81 static struct sr_dev_driver devantech_eth008_driver_info;
82
83 static struct sr_dev_inst *probe_device_conn(const char *conn)
84 {
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;
93         size_t ch_idx, nr, do_idx, di_idx, ai_idx;
94         struct sr_channel_group *cg;
95         char cg_name[24];
96         int ret;
97
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         }
140
141         ch_idx = 0;
142         devc->mask_do = (1UL << devc->model->ch_count_do) - 1;
143         devc->mask_do &= ~devc->model->mask_do_missing;
144         for (do_idx = 0; do_idx < devc->model->ch_count_do; do_idx++) {
145                 nr = do_idx + 1;
146                 if (devc->model->mask_do_missing & (1UL << do_idx))
147                         continue;
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         }
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         }
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
193 probe_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;
207 }
208
209 static GSList *scan(struct sr_dev_driver *di, GSList *options)
210 {
211         struct drv_context *drvc;
212         const char *conn;
213         GSList *devices;
214         struct sr_dev_inst *sdi;
215
216         drvc = di->context;
217         drvc->instances = NULL;
218
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);
231 }
232
233 static int config_get(uint32_t key, GVariant **data,
234         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
235 {
236         struct channel_group_context *cgc;
237         gboolean on;
238         uint16_t vin;
239         double vsupply;
240         int ret;
241
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         }
253
254         cgc = cg->priv;
255         if (!cgc)
256                 return SR_ERR_NA;
257         switch (key) {
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                 }
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                 }
273                 return SR_ERR_NA;
274         case SR_CONF_VOLTAGE:
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                 }
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;
292         default:
293                 return SR_ERR_NA;
294         }
295 }
296
297 static int config_set(uint32_t key, GVariant *data,
298         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
299 {
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         }
313
314         cgc = cg->priv;
315         if (!cgc)
316                 return SR_ERR_NA;
317         switch (key) {
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);
323         default:
324                 return SR_ERR_NA;
325         }
326 }
327
328 static int config_list(uint32_t key, GVariant **data,
329         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
330 {
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         }
343
344         cgc = cg->priv;
345         if (!cgc)
346                 return SR_ERR_NA;
347         switch (key) {
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                 }
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                 }
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;
366         default:
367                 return SR_ERR_NA;
368         }
369 }
370
371 static 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,
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,
387         .context = NULL,
388 };
389 SR_REGISTER_DEV_DRIVER(devantech_eth008_driver_info);