]> sigrok.org Git - libsigrok.git/blob - hardware/agilent-dmm/sched.c
Always interleave analog data with all enabled probes.
[libsigrok.git] / hardware / agilent-dmm / sched.c
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2012 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 <glib.h>
21 #include "libsigrok.h"
22 #include "libsigrok-internal.h"
23 #include "agilent-dmm.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <math.h>
28
29 static void dispatch(const struct sr_dev_inst *sdi)
30 {
31         struct dev_context *devc;
32         const struct agdmm_job *jobs;
33         int64_t now;
34         int i;
35
36         devc = sdi->priv;
37         jobs = devc->profile->jobs;
38         now = g_get_monotonic_time() / 1000;
39         for (i = 0; (&jobs[i])->interval; i++) {
40                 if (now - devc->jobqueue[i] > (&jobs[i])->interval) {
41                         sr_spew("Running job %d.", i);
42                         (&jobs[i])->send(sdi);
43                         devc->jobqueue[i] = now;
44                 }
45         }
46 }
47
48 static void receive_line(const struct sr_dev_inst *sdi)
49 {
50         struct dev_context *devc;
51         const struct agdmm_recv *recvs, *recv;
52         GRegex *reg;
53         GMatchInfo *match;
54         int i;
55
56         devc = sdi->priv;
57
58         /* Strip CRLF */
59         while (devc->buflen) {
60                 if (*(devc->buf + devc->buflen - 1) == '\r'
61                                 || *(devc->buf + devc->buflen - 1) == '\n')
62                         *(devc->buf + --devc->buflen) = '\0';
63                 else
64                         break;
65         }
66         sr_spew("Received '%s'.", devc->buf);
67
68         recv = NULL;
69         recvs = devc->profile->recvs;
70         for (i = 0; (&recvs[i])->recv_regex; i++) {
71                 reg = g_regex_new((&recvs[i])->recv_regex, 0, 0, NULL);
72                 if (g_regex_match(reg, (char *)devc->buf, 0, &match)) {
73                         recv = &recvs[i];
74                         break;
75                 }
76                 g_match_info_unref(match);
77                 g_regex_unref(reg);
78         }
79         if (recv) {
80                 recv->recv(sdi, match);
81                 g_match_info_unref(match);
82                 g_regex_unref(reg);
83         } else
84                 sr_dbg("Unknown line '%s'.", devc->buf);
85
86         /* Done with this. */
87         devc->buflen = 0;
88 }
89
90 SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data)
91 {
92         struct sr_dev_inst *sdi;
93         struct dev_context *devc;
94         int len;
95
96         (void)fd;
97
98         if (!(sdi = cb_data))
99                 return TRUE;
100
101         if (!(devc = sdi->priv))
102                 return TRUE;
103
104         if (revents == G_IO_IN) {
105                 /* Serial data arrived. */
106                 while(AGDMM_BUFSIZE - devc->buflen - 1 > 0) {
107                         len = serial_read(devc->serial, devc->buf + devc->buflen, 1);
108                         if (len < 1)
109                                 break;
110                         devc->buflen += len;
111                         *(devc->buf + devc->buflen) = '\0';
112                         if (*(devc->buf + devc->buflen - 1) == '\n') {
113                                 /* End of line */
114                                 receive_line(sdi);
115                                 break;
116                         }
117                 }
118         }
119
120         dispatch(sdi);
121
122         if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
123                 sdi->driver->dev_acquisition_stop(sdi, cb_data);
124
125         return TRUE;
126 }
127
128 static int agdmm_send(const struct sr_dev_inst *sdi, const char *cmd)
129 {
130         struct dev_context *devc;
131         char buf[32];
132
133         devc = sdi->priv;
134         sr_spew("Sending '%s'.", cmd);
135         strncpy(buf, cmd, 28);
136         if (!strncmp(buf, "*IDN?", 5))
137                 strncat(buf, "\r\n", 32);
138         else
139                 strncat(buf, "\n\r\n", 32);
140         if (serial_write(devc->serial, buf, strlen(buf)) == -1) {
141                 sr_err("Failed to send: %s.", strerror(errno));
142                 return SR_ERR;
143         }
144         
145         return SR_OK;
146 }
147
148 static int send_stat(const struct sr_dev_inst *sdi)
149 {
150         return agdmm_send(sdi, "STAT?");
151 }
152
153 static int recv_stat_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
154 {
155         struct dev_context *devc;
156         char *s;
157
158         devc = sdi->priv;
159         s = g_match_info_fetch(match, 1);
160         sr_spew("STAT response '%s'.", s);
161
162         /* Max, Min or Avg mode -- no way to tell which, so we'll
163          * set both flags to denote it's not a normal measurement. */
164         if (s[0] == '1')
165                 devc->cur_mqflags |= SR_MQFLAG_MAX | SR_MQFLAG_MIN;
166         else
167                 devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN);
168
169         if (s[1] == '1')
170                 devc->cur_mqflags |= SR_MQFLAG_RELATIVE;
171         else
172                 devc->cur_mqflags &= ~SR_MQFLAG_RELATIVE;
173
174         /* Triggered or auto hold modes. */
175         if (s[2] == '1' || s[3] == '1')
176                 devc->cur_mqflags |= SR_MQFLAG_HOLD;
177         else
178                 devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
179
180         /* Temp/aux mode. */
181         if (s[7] == '1')
182                 devc->mode_tempaux = TRUE;
183         else
184                 devc->mode_tempaux = FALSE;
185
186         /* Continuity mode. */
187         if (s[16] == '1')
188                 devc->mode_continuity = TRUE;
189         else
190                 devc->mode_continuity = FALSE;
191
192         g_free(s);
193
194         return SR_OK;
195 }
196
197 static int recv_stat_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
198 {
199         struct dev_context *devc;
200         char *s;
201
202         devc = sdi->priv;
203         s = g_match_info_fetch(match, 1);
204         sr_spew("STAT response '%s'.", s);
205
206         /* Peak hold mode. */
207         if (s[4] == '1')
208                 devc->cur_mqflags |= SR_MQFLAG_MAX;
209         else
210                 devc->cur_mqflags &= ~SR_MQFLAG_MAX;
211
212         /* Triggered hold mode. */
213         if (s[7] == '1')
214                 devc->cur_mqflags |= SR_MQFLAG_HOLD;
215         else
216                 devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
217
218         g_free(s);
219
220         return SR_OK;
221 }
222
223 static int send_fetc(const struct sr_dev_inst *sdi)
224 {
225         return agdmm_send(sdi, "FETC?");
226 }
227
228 static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match)
229 {
230         struct dev_context *devc;
231         struct sr_datafeed_packet packet;
232         struct sr_datafeed_analog analog;
233         float fvalue;
234         char *mstr, *eptr;
235
236         sr_spew("FETC reply '%s'.", g_match_info_get_string(match));
237         devc = sdi->priv;
238
239         if (devc->cur_mq == -1)
240                 /* Haven't seen configuration yet, so can't know what
241                  * the fetched float means. Not really an error, we'll
242                  * get metadata soon enough. */
243                 return SR_OK;
244
245         if (!strcmp(g_match_info_get_string(match), "+9.90000000E+37")) {
246                 /* An invalid measurement shows up on the display as "O.L", but
247                  * comes through like this. Since comparing 38-digit floats
248                  * is rather problematic, we'll cut through this here. */
249                 fvalue = NAN;
250         } else {
251                 mstr = g_match_info_fetch(match, 1);
252                 fvalue = strtof(mstr, &eptr);
253                 g_free(mstr);
254                 if (fvalue == 0.0 && eptr == mstr) {
255                         sr_err("Invalid float.");
256                         return SR_ERR;
257                 }
258                 if (devc->cur_divider > 0)
259                         fvalue /= devc->cur_divider;
260         }
261
262         memset(&analog, 0, sizeof(struct sr_datafeed_analog));
263         analog.mq = devc->cur_mq;
264         analog.unit = devc->cur_unit;
265         analog.mqflags = devc->cur_mqflags;
266         analog.probes = sdi->probes;
267         analog.num_samples = 1;
268         analog.data = &fvalue;
269         packet.type = SR_DF_ANALOG;
270         packet.payload = &analog;
271         sr_session_send(devc->cb_data, &packet);
272
273         devc->num_samples++;
274
275         return SR_OK;
276 }
277
278 static int send_conf(const struct sr_dev_inst *sdi)
279 {
280         return agdmm_send(sdi, "CONF?");
281 }
282
283 static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
284 {
285         struct dev_context *devc;
286         char *mstr;
287
288         sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
289         devc = sdi->priv;
290         mstr = g_match_info_fetch(match, 1);
291         if (!strcmp(mstr, "V")) {
292                 devc->cur_mq = SR_MQ_VOLTAGE;
293                 devc->cur_unit = SR_UNIT_VOLT;
294                 devc->cur_mqflags = 0;
295                 devc->cur_divider = 0;
296         } else if(!strcmp(mstr, "MV")) {
297                 if (devc->mode_tempaux) {
298                         devc->cur_mq = SR_MQ_TEMPERATURE;
299                         /* No way to detect whether Fahrenheit or Celcius
300                          * is used, so we'll just default to Celcius. */
301                         devc->cur_unit = SR_UNIT_CELSIUS;
302                 devc->cur_mqflags = 0;
303                 devc->cur_divider = 0;
304                 } else {
305                         devc->cur_mq = SR_MQ_VOLTAGE;
306                         devc->cur_unit = SR_UNIT_VOLT;
307                         devc->cur_mqflags = 0;
308                         devc->cur_divider = 1000;
309                 }
310         } else if(!strcmp(mstr, "A")) {
311                 devc->cur_mq = SR_MQ_CURRENT;
312                 devc->cur_unit = SR_UNIT_AMPERE;
313                 devc->cur_mqflags = 0;
314                 devc->cur_divider = 0;
315         } else if(!strcmp(mstr, "UA")) {
316                 devc->cur_mq = SR_MQ_CURRENT;
317                 devc->cur_unit = SR_UNIT_AMPERE;
318                 devc->cur_mqflags = 0;
319                 devc->cur_divider = 1000000;
320         } else if(!strcmp(mstr, "FREQ")) {
321                 devc->cur_mq = SR_MQ_FREQUENCY;
322                 devc->cur_unit = SR_UNIT_HERTZ;
323                 devc->cur_mqflags = 0;
324                 devc->cur_divider = 0;
325         } else if(!strcmp(mstr, "RES")) {
326                 if (devc->mode_continuity) {
327                         devc->cur_mq = SR_MQ_CONTINUITY;
328                         devc->cur_unit = SR_UNIT_BOOLEAN;
329                 } else {
330                         devc->cur_mq = SR_MQ_RESISTANCE;
331                         devc->cur_unit = SR_UNIT_OHM;
332                 }
333                 devc->cur_mqflags = 0;
334                 devc->cur_divider = 0;
335         } else if(!strcmp(mstr, "CAP")) {
336                 devc->cur_mq = SR_MQ_CAPACITANCE;
337                 devc->cur_unit = SR_UNIT_FARAD;
338                 devc->cur_mqflags = 0;
339                 devc->cur_divider = 0;
340         } else
341                 sr_dbg("Unknown first argument.");
342         g_free(mstr);
343
344         if (g_match_info_get_match_count(match) == 4) {
345                 mstr = g_match_info_fetch(match, 3);
346                 /* Third value, if present, is always AC or DC. */
347                 if (!strcmp(mstr, "AC"))
348                         devc->cur_mqflags |= SR_MQFLAG_AC;
349                 else if (!strcmp(mstr, "DC"))
350                         devc->cur_mqflags |= SR_MQFLAG_DC;
351                 else
352                         sr_dbg("Unknown third argument.");
353                 g_free(mstr);
354         } else
355                 devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
356
357         return SR_OK;
358 }
359
360 static int recv_conf_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
361 {
362         struct dev_context *devc;
363         char *mstr;
364
365         sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
366         devc = sdi->priv;
367         mstr = g_match_info_fetch(match, 1);
368         if (!strncmp(mstr, "VOLT", 4)) {
369                 devc->cur_mq = SR_MQ_VOLTAGE;
370                 devc->cur_unit = SR_UNIT_VOLT;
371                 devc->cur_mqflags = 0;
372                 devc->cur_divider = 0;
373                 if (mstr[4] == ':') {
374                         if (!strcmp(mstr + 4, "AC"))
375                                 devc->cur_mqflags |= SR_MQFLAG_AC;
376                         else if (!strcmp(mstr + 4, "DC"))
377                                 devc->cur_mqflags |= SR_MQFLAG_DC;
378                         else
379                                 /* "ACDC" appears as well, no idea what it means. */
380                                 devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
381                 } else
382                         devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
383         } else if(!strcmp(mstr, "CURR")) {
384                 devc->cur_mq = SR_MQ_CURRENT;
385                 devc->cur_unit = SR_UNIT_AMPERE;
386                 devc->cur_mqflags = 0;
387                 devc->cur_divider = 0;
388         } else if(!strcmp(mstr, "RES")) {
389                 if (devc->mode_continuity) {
390                         devc->cur_mq = SR_MQ_CONTINUITY;
391                         devc->cur_unit = SR_UNIT_BOOLEAN;
392                 } else {
393                         devc->cur_mq = SR_MQ_RESISTANCE;
394                         devc->cur_unit = SR_UNIT_OHM;
395                 }
396                 devc->cur_mqflags = 0;
397                 devc->cur_divider = 0;
398         } else
399                 sr_dbg("Unknown first argument.");
400         g_free(mstr);
401
402         return SR_OK;
403 }
404
405 /* At least the 123x and 125x appear to have this. */
406 static int recv_conf(const struct sr_dev_inst *sdi, GMatchInfo *match)
407 {
408         struct dev_context *devc;
409         char *mstr;
410
411         sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
412         devc = sdi->priv;
413         mstr = g_match_info_fetch(match, 1);
414         if(!strcmp(mstr, "DIOD")) {
415                 devc->cur_mq = SR_MQ_VOLTAGE;
416                 devc->cur_unit = SR_UNIT_VOLT;
417                 devc->cur_mqflags = SR_MQFLAG_DIODE;
418                 devc->cur_divider = 0;
419         } else
420                 sr_dbg("Unknown single argument.");
421         g_free(mstr);
422
423         return SR_OK;
424 }
425
426 /* This comes in whenever the rotary switch is changed to a new position.
427  * We could use it to determine the major measurement mode, but we already
428  * have the output of CONF? for that, which is more detailed. However
429  * we do need to catch this here, or it'll show up in some other output. */
430 static int recv_switch(const struct sr_dev_inst *sdi, GMatchInfo *match)
431 {
432         (void)sdi;
433
434         sr_spew("Switch '%s'.", g_match_info_get_string(match));
435
436         return SR_OK;
437 }
438
439 SR_PRIV const struct agdmm_job agdmm_jobs_u123x[] = {
440         { 143, send_stat },
441         { 1000, send_conf },
442         { 143, send_fetc },
443         { 0, NULL }
444 };
445
446 SR_PRIV const struct agdmm_recv agdmm_recvs_u123x[] = {
447         { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u123x },
448         { "^\\*([0-9])$", recv_switch },
449         { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
450         { "^\"(V|MV|A|UA|FREQ),(\\d),(AC|DC)\"$", recv_conf_u123x },
451         { "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x},
452         { "^\"(DIOD)\"$", recv_conf },
453         { NULL, NULL }
454 };
455
456 SR_PRIV const struct agdmm_job agdmm_jobs_u125x[] = {
457         { 143, send_stat },
458         { 1000, send_conf },
459         { 143, send_fetc },
460         { 0, NULL }
461 };
462
463 SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
464         { "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
465         { "^\\*([0-9])$", recv_switch },
466         { "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
467         { "^(VOLT|CURR|RES|CAP) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
468         { "^(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
469         { "^\"(DIOD)\"$", recv_conf },
470         { NULL, NULL }
471 };