]> sigrok.org Git - libsigrok.git/blame - src/hardware/atten-pps3xxx/api.c
Pass driver struct pointer to driver callbacks.
[libsigrok.git] / src / hardware / atten-pps3xxx / api.c
CommitLineData
fa0d6afe
BV
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2014 Bert Vermeulen <bert@biot.com>
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
33c40990
BV
20#include <string.h>
21#include <errno.h>
fa0d6afe
BV
22#include "protocol.h"
23
33c40990
BV
24/*
25 * The default serial communication settings on the device are 9600
26 * baud, 9 data bits. The 9th bit isn't actually used, and the vendor
27 * software uses Mark parity to absorb the extra bit.
28 *
29 * Since 9 data bits is not a standard available in POSIX, we use two
30 * stop bits to skip over the extra bit instead.
31 */
32#define SERIALCOMM "9600/8n2"
33
584560f1 34static const uint32_t scanopts[] = {
33c40990
BV
35 SR_CONF_CONN,
36 SR_CONF_SERIALCOMM,
37};
38
1f889afd 39static const uint32_t drvopts[] = {
33c40990 40 SR_CONF_POWER_SUPPLY,
d6fa8ace
BV
41};
42
1f889afd
BV
43static const uint32_t devopts[] = {
44 SR_CONF_CONTINUOUS | SR_CONF_SET,
5827f61b
BV
45 SR_CONF_OUTPUT_CHANNEL_CONFIG | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
46 SR_CONF_OVER_CURRENT_PROTECTION_ENABLED | SR_CONF_GET | SR_CONF_SET,
33c40990
BV
47};
48
584560f1 49static const uint32_t devopts_cg[] = {
5827f61b 50 SR_CONF_OUTPUT_VOLTAGE | SR_CONF_GET,
ca95e90f 51 SR_CONF_OUTPUT_VOLTAGE_TARGET | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
5827f61b 52 SR_CONF_OUTPUT_CURRENT | SR_CONF_GET,
ca95e90f 53 SR_CONF_OUTPUT_CURRENT_LIMIT | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
5827f61b 54 SR_CONF_OUTPUT_ENABLED | SR_CONF_GET | SR_CONF_SET,
33c40990
BV
55};
56
57static const char *channel_modes[] = {
58 "Independent",
59 "Series",
60 "Parallel",
61};
62
63static struct pps_model models[] = {
64 { PPS_3203T_3S, "PPS3203T-3S",
65 CHANMODE_INDEPENDENT | CHANMODE_SERIES | CHANMODE_PARALLEL,
66 3,
67 {
68 /* Channel 1 */
69 { { 0, 32, 0.01 }, { 0, 3, 0.001 } },
70 /* Channel 2 */
71 { { 0, 32, 0.01 }, { 0, 3, 0.001 } },
72 /* Channel 3 */
73 { { 0, 6, 0.01 }, { 0, 3, 0.001 } },
74 },
75 },
76};
77
78
79SR_PRIV struct sr_dev_driver atten_pps3203_driver_info;
fa0d6afe 80
4f840ce9 81static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx)
fa0d6afe
BV
82{
83 return std_init(sr_ctx, di, LOG_PREFIX);
84}
85
4f840ce9 86static GSList *scan(struct sr_dev_driver *di, GSList *options, int modelid)
fa0d6afe 87{
33c40990 88 struct sr_dev_inst *sdi;
fa0d6afe 89 struct drv_context *drvc;
33c40990
BV
90 struct dev_context *devc;
91 struct sr_config *src;
ba7dd8bb 92 struct sr_channel *ch;
40fd0264 93 struct sr_channel_group *cg;
33c40990
BV
94 struct sr_serial_dev_inst *serial;
95 GSList *l, *devices;
96 struct pps_model *model;
97 uint8_t packet[PACKET_SIZE];
98 unsigned int i;
2eb1612d 99 int delay_ms, ret;
33c40990
BV
100 const char *conn, *serialcomm;
101 char channel[10];
fa0d6afe
BV
102
103 devices = NULL;
104 drvc = di->priv;
105 drvc->instances = NULL;
106
33c40990
BV
107 conn = serialcomm = NULL;
108 for (l = options; l; l = l->next) {
109 src = l->data;
110 switch (src->key) {
111 case SR_CONF_CONN:
112 conn = g_variant_get_string(src->data, NULL);
113 break;
114 case SR_CONF_SERIALCOMM:
115 serialcomm = g_variant_get_string(src->data, NULL);
116 break;
117 }
118 }
119 if (!conn)
120 return NULL;
121 if (!serialcomm)
122 serialcomm = SERIALCOMM;
123
91219afc 124 serial = sr_serial_dev_inst_new(conn, serialcomm);
33c40990 125
5305266a 126 if (serial_open(serial, SERIAL_RDWR) != SR_OK)
33c40990 127 return NULL;
91219afc 128
33c40990
BV
129 serial_flush(serial);
130
945cfd4f 131 /* This is how the vendor software scans for hardware. */
33c40990
BV
132 memset(packet, 0, PACKET_SIZE);
133 packet[0] = 0xaa;
134 packet[1] = 0xaa;
2eb1612d
BV
135 delay_ms = serial_timeout(serial, PACKET_SIZE);
136 if (serial_write_blocking(serial, packet, PACKET_SIZE, delay_ms) < PACKET_SIZE) {
081c214e 137 sr_err("Unable to write while probing for hardware.");
33c40990
BV
138 return NULL;
139 }
140 /* The device responds with a 24-byte packet when it receives a packet.
141 * At 9600 baud, 300ms is long enough for it to have arrived. */
142 g_usleep(300 * 1000);
143 memset(packet, 0, PACKET_SIZE);
144 if ((ret = serial_read_nonblocking(serial, packet, PACKET_SIZE)) < 0) {
145 sr_err("Unable to read while probing for hardware: %s",
146 strerror(errno));
147 return NULL;
148 }
149 if (ret != PACKET_SIZE || packet[0] != 0xaa || packet[1] != 0xaa) {
150 /* Doesn't look like an Atten PPS. */
151 return NULL;
152 }
153
154 model = NULL;
155 for (i = 0; i < ARRAY_SIZE(models); i++) {
156 if (models[i].modelid == modelid) {
157 model = &models[i];
158 break;
159 }
160 }
161 if (!model) {
162 sr_err("Unknown modelid %d", modelid);
163 return NULL;
164 }
165
aac29cc1 166 sdi = g_malloc0(sizeof(struct sr_dev_inst));
0af636be
UH
167 sdi->status = SR_ST_INACTIVE;
168 sdi->vendor = g_strdup("Atten");
169 sdi->model = g_strdup(model->name);
33c40990
BV
170 sdi->driver = di;
171 sdi->inst_type = SR_INST_SERIAL;
172 sdi->conn = serial;
173 for (i = 0; i < MAX_CHANNELS; i++) {
174 snprintf(channel, 10, "CH%d", i + 1);
5e23fcab 175 ch = sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, channel);
40fd0264
UH
176 cg = g_malloc(sizeof(struct sr_channel_group));
177 cg->name = g_strdup(channel);
ba7dd8bb 178 cg->channels = g_slist_append(NULL, ch);
40fd0264
UH
179 cg->priv = NULL;
180 sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
33c40990
BV
181 }
182
183 devc = g_malloc0(sizeof(struct dev_context));
184 devc->model = model;
185 devc->config = g_malloc0(sizeof(struct per_channel_config) * model->num_channels);
2eb1612d 186 devc->delay_ms = delay_ms;
33c40990
BV
187 sdi->priv = devc;
188 drvc->instances = g_slist_append(drvc->instances, sdi);
189 devices = g_slist_append(devices, sdi);
190
191 serial_close(serial);
192 if (!devices)
193 sr_serial_dev_inst_free(serial);
fa0d6afe
BV
194
195 return devices;
196}
197
4f840ce9 198static GSList *scan_3203(struct sr_dev_driver *di, GSList *options)
33c40990 199{
4f840ce9 200 return scan(di, options, PPS_3203T_3S);
33c40990
BV
201}
202
4f840ce9 203static GSList *dev_list(const struct sr_dev_driver *di)
fa0d6afe
BV
204{
205 return ((struct drv_context *)(di->priv))->instances;
206}
207
4f840ce9 208static int cleanup(const struct sr_dev_driver *di)
fa0d6afe 209{
a6630742 210 return std_dev_clear(di, NULL);
fa0d6afe
BV
211}
212
584560f1 213static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
53b4680f 214 const struct sr_channel_group *cg)
fa0d6afe 215{
33c40990 216 struct dev_context *devc;
ba7dd8bb 217 struct sr_channel *ch;
33c40990
BV
218 int channel, ret;
219
220 if (!sdi)
221 return SR_ERR_ARG;
fa0d6afe 222
33c40990 223 devc = sdi->priv;
fa0d6afe
BV
224
225 ret = SR_OK;
53b4680f 226 if (!cg) {
660e398f 227 /* No channel group: global options. */
33c40990 228 switch (key) {
a1eaa9e0 229 case SR_CONF_OUTPUT_CHANNEL_CONFIG:
fe997353 230 *data = g_variant_new_string(channel_modes[devc->channel_mode]);
33c40990 231 break;
a1eaa9e0 232 case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
33c40990
BV
233 *data = g_variant_new_boolean(devc->over_current_protection);
234 break;
235 default:
236 return SR_ERR_NA;
237 }
238 } else {
660e398f 239 /* We only ever have one channel per channel group in this driver. */
ba7dd8bb
UH
240 ch = cg->channels->data;
241 channel = ch->index;
33c40990
BV
242
243 switch (key) {
244 case SR_CONF_OUTPUT_VOLTAGE:
245 *data = g_variant_new_double(devc->config[channel].output_voltage_last);
246 break;
ca95e90f 247 case SR_CONF_OUTPUT_VOLTAGE_TARGET:
33c40990
BV
248 *data = g_variant_new_double(devc->config[channel].output_voltage_max);
249 break;
250 case SR_CONF_OUTPUT_CURRENT:
251 *data = g_variant_new_double(devc->config[channel].output_current_last);
252 break;
ca95e90f 253 case SR_CONF_OUTPUT_CURRENT_LIMIT:
33c40990
BV
254 *data = g_variant_new_double(devc->config[channel].output_current_max);
255 break;
256 case SR_CONF_OUTPUT_ENABLED:
257 *data = g_variant_new_boolean(devc->config[channel].output_enabled);
258 break;
259 default:
260 return SR_ERR_NA;
261 }
fa0d6afe
BV
262 }
263
264 return ret;
265}
266
33c40990
BV
267static int find_str(const char *str, const char **strings, int array_size)
268{
269 int idx, i;
270
271 idx = -1;
272 for (i = 0; i < array_size; i++) {
273 if (!strcmp(str, strings[i])) {
274 idx = i;
275 break;
276 }
277 }
278
279 return idx;
280}
281
584560f1 282static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi,
53b4680f 283 const struct sr_channel_group *cg)
fa0d6afe 284{
33c40990 285 struct dev_context *devc;
ba7dd8bb 286 struct sr_channel *ch;
33c40990
BV
287 gdouble dval;
288 int channel, ret, ival;
289 const char *sval;
290 gboolean bval;
fa0d6afe
BV
291
292 if (sdi->status != SR_ST_ACTIVE)
293 return SR_ERR_DEV_CLOSED;
294
295 ret = SR_OK;
33c40990 296 devc = sdi->priv;
53b4680f 297 if (!cg) {
660e398f 298 /* No channel group: global options. */
33c40990 299 switch (key) {
a1eaa9e0 300 case SR_CONF_OUTPUT_CHANNEL_CONFIG:
33c40990
BV
301 sval = g_variant_get_string(data, NULL);
302 if ((ival = find_str(sval, channel_modes,
303 ARRAY_SIZE(channel_modes))) == -1) {
304 ret = SR_ERR_ARG;
305 break;
306 }
307 if (devc->model->channel_modes && (1 << ival) == 0) {
308 /* Not supported on this model. */
309 ret = SR_ERR_ARG;
310 }
311 if (ival == devc->channel_mode_set)
312 /* Nothing to do. */
313 break;
314 devc->channel_mode_set = ival;
ab988ecb 315 devc->config_dirty = TRUE;
33c40990 316 break;
a1eaa9e0 317 case SR_CONF_OVER_CURRENT_PROTECTION_ENABLED:
33c40990
BV
318 bval = g_variant_get_boolean(data);
319 if (bval == devc->over_current_protection_set)
320 /* Nothing to do. */
321 break;
322 devc->over_current_protection_set = bval;
ab988ecb 323 devc->config_dirty = TRUE;
33c40990
BV
324 break;
325 default:
326 return SR_ERR_NA;
327 }
328 } else {
660e398f
UH
329 /* Channel group specified: per-channel options. */
330 /* We only ever have one channel per channel group in this driver. */
ba7dd8bb
UH
331 ch = cg->channels->data;
332 channel = ch->index;
33c40990
BV
333
334 switch (key) {
ca95e90f 335 case SR_CONF_OUTPUT_VOLTAGE_TARGET:
33c40990
BV
336 dval = g_variant_get_double(data);
337 if (dval < 0 || dval > devc->model->channels[channel].voltage[1])
338 ret = SR_ERR_ARG;
339 devc->config[channel].output_voltage_max = dval;
ab988ecb 340 devc->config_dirty = TRUE;
33c40990 341 break;
ca95e90f 342 case SR_CONF_OUTPUT_CURRENT_LIMIT:
33c40990
BV
343 dval = g_variant_get_double(data);
344 if (dval < 0 || dval > devc->model->channels[channel].current[1])
345 ret = SR_ERR_ARG;
346 devc->config[channel].output_current_max = dval;
ab988ecb 347 devc->config_dirty = TRUE;
33c40990
BV
348 break;
349 case SR_CONF_OUTPUT_ENABLED:
350 bval = g_variant_get_boolean(data);
351 if (bval == devc->config[channel].output_enabled_set)
352 /* Nothing to do. */
353 break;
354 devc->config[channel].output_enabled_set = bval;
ab988ecb 355 devc->config_dirty = TRUE;
33c40990
BV
356 break;
357 default:
358 ret = SR_ERR_NA;
359 }
fa0d6afe
BV
360 }
361
33c40990 362
fa0d6afe
BV
363 return ret;
364}
365
584560f1 366static int config_list(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi,
53b4680f 367 const struct sr_channel_group *cg)
fa0d6afe 368{
33c40990 369 struct dev_context *devc;
ba7dd8bb 370 struct sr_channel *ch;
33c40990
BV
371 GVariant *gvar;
372 GVariantBuilder gvb;
373 int channel, ret, i;
374
d6fa8ace 375 /* Always available. */
33c40990 376 if (key == SR_CONF_SCAN_OPTIONS) {
584560f1
BV
377 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
378 scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t));
33c40990
BV
379 return SR_OK;
380 }
381
d6fa8ace
BV
382 if (key == SR_CONF_DEVICE_OPTIONS && !sdi) {
383 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
1f889afd 384 drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t));
d6fa8ace
BV
385 return SR_OK;
386 }
387
e22aa878
BV
388 if (!sdi)
389 return SR_ERR_ARG;
fa0d6afe 390
d6fa8ace 391 devc = sdi->priv;
fa0d6afe 392 ret = SR_OK;
53b4680f 393 if (!cg) {
660e398f 394 /* No channel group: global options. */
33c40990
BV
395 switch (key) {
396 case SR_CONF_DEVICE_OPTIONS:
584560f1 397 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
1f889afd 398 devopts, ARRAY_SIZE(devopts), sizeof(uint32_t));
33c40990 399 break;
a1eaa9e0 400 case SR_CONF_OUTPUT_CHANNEL_CONFIG:
33c40990
BV
401 if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
402 /* The 1-channel models. */
403 *data = g_variant_new_strv(channel_modes, 1);
404 } else {
405 /* The other models support all modes. */
406 *data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
407 }
408 break;
409 default:
410 return SR_ERR_NA;
411 }
412 } else {
660e398f 413 /* Channel group specified: per-channel options. */
33c40990
BV
414 if (!sdi)
415 return SR_ERR_ARG;
660e398f 416 /* We only ever have one channel per channel group in this driver. */
ba7dd8bb
UH
417 ch = cg->channels->data;
418 channel = ch->index;
33c40990
BV
419
420 switch (key) {
421 case SR_CONF_DEVICE_OPTIONS:
584560f1
BV
422 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
423 devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(uint32_t));
33c40990 424 break;
ca95e90f 425 case SR_CONF_OUTPUT_VOLTAGE_TARGET:
33c40990
BV
426 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
427 /* Min, max, step. */
428 for (i = 0; i < 3; i++) {
429 gvar = g_variant_new_double(devc->model->channels[channel].voltage[i]);
430 g_variant_builder_add_value(&gvb, gvar);
431 }
432 *data = g_variant_builder_end(&gvb);
433 break;
ca95e90f 434 case SR_CONF_OUTPUT_CURRENT_LIMIT:
33c40990
BV
435 g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
436 /* Min, max, step. */
437 for (i = 0; i < 3; i++) {
438 gvar = g_variant_new_double(devc->model->channels[channel].current[i]);
439 g_variant_builder_add_value(&gvb, gvar);
440 }
441 *data = g_variant_builder_end(&gvb);
442 break;
443 default:
444 return SR_ERR_NA;
445 }
fa0d6afe
BV
446 }
447
448 return ret;
449}
450
ab988ecb
BV
451static int dev_close(struct sr_dev_inst *sdi)
452{
453 struct dev_context *devc;
454
455 devc = sdi->priv;
456 if (devc->config_dirty)
457 /* Some configuration changes were queued up but didn't
458 * get sent to the device, likely because we were never
459 * in acquisition mode. Send them out now. */
460 send_config(sdi);
461
462 return std_serial_dev_close(sdi);
463}
464
fa0d6afe 465static int dev_acquisition_start(const struct sr_dev_inst *sdi,
33c40990 466 void *cb_data)
fa0d6afe 467{
33c40990
BV
468 struct dev_context *devc;
469 struct sr_serial_dev_inst *serial;
470 uint8_t packet[PACKET_SIZE];
471
fa0d6afe
BV
472 (void)cb_data;
473
474 if (sdi->status != SR_ST_ACTIVE)
475 return SR_ERR_DEV_CLOSED;
476
33c40990
BV
477 devc = sdi->priv;
478 memset(devc->packet, 0x44, PACKET_SIZE);
479 devc->packet_size = 0;
480
481 devc->acquisition_running = TRUE;
482
483 serial = sdi->conn;
102f1239
BV
484 serial_source_add(sdi->session, serial, G_IO_IN, 50,
485 atten_pps3xxx_receive_data, (void *)sdi);
33c40990
BV
486 std_session_send_df_header(cb_data, LOG_PREFIX);
487
ba7dd8bb 488 /* Send a "channel" configuration packet now. */
33c40990
BV
489 memset(packet, 0, PACKET_SIZE);
490 packet[0] = 0xaa;
491 packet[1] = 0xaa;
492 send_packet(sdi, packet);
fa0d6afe
BV
493
494 return SR_OK;
495}
496
497static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
498{
33c40990
BV
499 struct dev_context *devc;
500
fa0d6afe
BV
501 (void)cb_data;
502
503 if (sdi->status != SR_ST_ACTIVE)
504 return SR_ERR_DEV_CLOSED;
505
33c40990
BV
506 devc = sdi->priv;
507 devc->acquisition_running = FALSE;
fa0d6afe
BV
508
509 return SR_OK;
510}
511
33c40990
BV
512SR_PRIV struct sr_dev_driver atten_pps3203_driver_info = {
513 .name = "atten-pps3203",
514 .longname = "Atten PPS3203T-3S",
fa0d6afe
BV
515 .api_version = 1,
516 .init = init,
517 .cleanup = cleanup,
33c40990 518 .scan = scan_3203,
fa0d6afe 519 .dev_list = dev_list,
a6630742 520 .dev_clear = NULL,
fa0d6afe
BV
521 .config_get = config_get,
522 .config_set = config_set,
523 .config_list = config_list,
33c40990 524 .dev_open = std_serial_dev_open,
ab988ecb 525 .dev_close = dev_close,
fa0d6afe
BV
526 .dev_acquisition_start = dev_acquisition_start,
527 .dev_acquisition_stop = dev_acquisition_stop,
528 .priv = NULL,
529};