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