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