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