]> sigrok.org Git - libsigrok.git/blob - src/hardware/baylibre-acme/protocol.c
Fix log varargs bugs indicated by -Wformat
[libsigrok.git] / src / hardware / baylibre-acme / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2015 Bartosz Golaszewski <bgolaszewski@baylibre.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 <stdlib.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <glib/gstdio.h>
25 #include "protocol.h"
26 #include "gpio.h"
27
28 struct channel_group_priv {
29         int hwmon_num;
30         int probe_type;
31         int index;
32 };
33
34 struct channel_priv {
35         int ch_type;
36         int fd;
37         float val;
38         struct channel_group_priv *probe;
39 };
40
41 static const uint8_t enrg_i2c_addrs[] = {
42         0x40, 0x41, 0x44, 0x45, 0x42, 0x43, 0x46, 0x47,
43 };
44
45 static const uint8_t temp_i2c_addrs[] = {
46         0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x4f, 0x4b,
47 };
48
49 static const uint32_t pws_gpios[] = {
50         486, 498, 502, 482, 478, 506, 510, 474,
51 };
52
53 static const uint32_t pws_info_gpios[] = {
54         487, 499, 503, 483, 479, 507, 511, 475,
55 };
56
57 #define MOHM_TO_UOHM(x) ((x) * 1000)
58 #define UOHM_TO_MOHM(x) ((x) / 1000)
59
60 SR_PRIV uint8_t bl_acme_get_enrg_addr(int index)
61 {
62         return enrg_i2c_addrs[index];
63 }
64
65 SR_PRIV uint8_t bl_acme_get_temp_addr(int index)
66 {
67         return temp_i2c_addrs[index];
68 }
69
70 SR_PRIV gboolean bl_acme_is_sane(void)
71 {
72         gboolean status;
73
74         /*
75          * We expect sysfs to be present and mounted at /sys, ina226 and
76          * tmp435 sensors detected by the system and their appropriate
77          * drivers loaded and functional.
78          */
79         status = g_file_test("/sys", G_FILE_TEST_IS_DIR);
80         if (!status) {
81                 sr_err("/sys/ directory not found - sysfs not mounted?");
82                 return FALSE;
83         }
84
85         return TRUE;
86 }
87
88 static void probe_name_path(unsigned int addr, GString *path)
89 {
90         g_string_printf(path,
91                         "/sys/class/i2c-adapter/i2c-1/1-00%02x/name", addr);
92 }
93
94 /*
95  * For given address fill buf with the path to appropriate hwmon entry.
96  */
97 static void probe_hwmon_path(unsigned int addr, GString *path)
98 {
99         g_string_printf(path,
100                         "/sys/class/i2c-adapter/i2c-1/1-00%02x/hwmon", addr);
101 }
102
103 SR_PRIV gboolean bl_acme_detect_probe(unsigned int addr,
104                                       int prb_num, const char *prb_name)
105 {
106         gboolean ret = FALSE, status;
107         char *buf = NULL;
108         GString *path = g_string_sized_new(64);
109         GError *err = NULL;
110         gsize size;
111
112         probe_name_path(addr, path);
113         status = g_file_get_contents(path->str, &buf, &size, &err);
114         if (!status) {
115                 sr_dbg("Name for probe %d can't be read: %s",
116                        prb_num, err->message);
117                 g_string_free(path, TRUE);
118                 return ret;
119         }
120
121         if (!strncmp(buf, prb_name, strlen(prb_name))) {
122                 /*
123                  * Correct driver registered on this address - but is
124                  * there an actual probe connected?
125                  */
126                 probe_hwmon_path(addr, path);
127                 status = g_file_test(path->str, G_FILE_TEST_IS_DIR);
128                 if (status) {
129                         /* We have found an ACME probe. */
130                         ret = TRUE;
131                 }
132         }
133
134         g_free(buf);
135         g_string_free(path, TRUE);
136
137         return ret;
138 }
139
140 static int get_hwmon_index(unsigned int addr)
141 {
142         int status, hwmon;
143         GString *path = g_string_sized_new(64);
144         GError *err = NULL;
145         GDir *dir;
146
147         probe_hwmon_path(addr, path);
148         dir = g_dir_open(path->str, 0, &err);
149         if (!dir) {
150                 sr_err("Error opening %s: %s", path->str, err->message);
151                 g_string_free(path, TRUE);
152                 return -1;
153         }
154
155         g_string_free(path, TRUE);
156
157         /*
158          * The directory should contain a single file named hwmonX where X
159          * is the hwmon index.
160          */
161         status = sscanf(g_dir_read_name(dir), "hwmon%d", &hwmon);
162         g_dir_close(dir);
163         if (status != 1) {
164                 sr_err("Unable to determine the hwmon entry");
165                 return -1;
166         }
167
168         return hwmon;
169 }
170
171 static void append_channel(struct sr_dev_inst *sdi, struct sr_channel_group *cg,
172                            int index, int type)
173 {
174         struct channel_priv *cp;
175         struct dev_context *devc;
176         struct sr_channel *ch;
177         char *name;
178
179         devc = sdi->priv;
180
181         switch (type) {
182         case ENRG_PWR:
183                 name = g_strdup_printf("P%d_ENRG_PWR", index);
184                 break;
185         case ENRG_CURR:
186                 name = g_strdup_printf("P%d_ENRG_CURR", index);
187                 break;
188         case ENRG_VOL:
189                 name = g_strdup_printf("P%d_ENRG_VOL", index);
190                 break;
191         case TEMP_IN:
192                 name = g_strdup_printf("P%d_TEMP_IN", index);
193                 break;
194         case TEMP_OUT:
195                 name = g_strdup_printf("P%d_TEMP_OUT", index);
196                 break;
197         default:
198                 sr_err("Invalid channel type: %d.", type);
199                 return;
200         }
201
202         cp = g_malloc0(sizeof(struct channel_priv));
203         cp->ch_type = type;
204         cp->probe = cg->priv;
205
206         ch = sr_channel_new(sdi, devc->num_channels++,
207                             SR_CHANNEL_ANALOG, TRUE, name);
208         g_free(name);
209
210         ch->priv = cp;
211         cg->channels = g_slist_append(cg->channels, ch);
212 }
213
214 SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type,
215                                         unsigned int addr, int prb_num)
216 {
217         struct sr_channel_group *cg;
218         struct channel_group_priv *cgp;
219         int hwmon;
220
221         /* Obtain the hwmon index. */
222         hwmon = get_hwmon_index(addr);
223         if (hwmon < 0)
224                 return FALSE;
225
226         cg = g_malloc0(sizeof(struct sr_channel_group));
227         cgp = g_malloc0(sizeof(struct channel_group_priv));
228         cgp->hwmon_num = hwmon;
229         cgp->probe_type = type;
230         cgp->index = prb_num - 1;
231         cg->name = g_strdup_printf("Probe_%d", prb_num);
232         cg->priv = cgp;
233
234         if (type == PROBE_ENRG) {
235                 append_channel(sdi, cg, prb_num, ENRG_PWR);
236                 append_channel(sdi, cg, prb_num, ENRG_CURR);
237                 append_channel(sdi, cg, prb_num, ENRG_VOL);
238         } else if (type == PROBE_TEMP) {
239                 append_channel(sdi, cg, prb_num, TEMP_IN);
240                 append_channel(sdi, cg, prb_num, TEMP_OUT);
241         } else {
242                 sr_err("Invalid probe type: %d.", type);
243         }
244
245         sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
246
247         return TRUE;
248 }
249
250 SR_PRIV int bl_acme_get_probe_type(const struct sr_channel_group *cg)
251 {
252         struct channel_group_priv *cgp = cg->priv;
253
254         return cgp->probe_type;
255 }
256
257 SR_PRIV int bl_acme_probe_has_pws(const struct sr_channel_group *cg)
258 {
259         struct channel_group_priv *cgp = cg->priv;
260
261         return sr_gpio_getval_export(pws_info_gpios[cgp->index]);
262 }
263
264 /*
265  * Sets path to the hwmon attribute if this channel group
266  * supports shunt resistance setting. The caller has to supply
267  * a valid GString.
268  */
269 static int get_shunt_path(const struct sr_channel_group *cg, GString *path)
270 {
271         struct channel_group_priv *cgp;
272         int ret = SR_OK, status;
273
274         cgp = cg->priv;
275
276         if (cgp->probe_type != PROBE_ENRG) {
277                 sr_err("Probe doesn't support shunt resistance setting");
278                 return SR_ERR_ARG;
279         }
280
281         g_string_append_printf(path,
282                                "/sys/class/hwmon/hwmon%d/shunt_resistor",
283                                cgp->hwmon_num);
284
285         /*
286          * The shunt_resistor sysfs attribute is available
287          * in the Linux kernel since version 3.20. We have
288          * to notify the user if this attribute is not present.
289          */
290         status = g_file_test(path->str, G_FILE_TEST_EXISTS);
291         if (!status) {
292                 sr_err("shunt_resistance attribute not present, please update "
293                        "your kernel to version >=3.20");
294                 return SR_ERR_NA;
295         }
296
297         return ret;
298 }
299
300 /*
301  * Try setting the update_interval sysfs attribute for each probe according
302  * to samplerate.
303  */
304 SR_PRIV void bl_acme_maybe_set_update_interval(const struct sr_dev_inst *sdi,
305                                                uint64_t samplerate)
306 {
307         struct sr_channel_group *cg;
308         struct channel_group_priv *cgp;
309         GString *hwmon;
310         GSList *l;
311         FILE *fd;
312
313         for (l = sdi->channel_groups; l != NULL; l = l->next) {
314                 cg = l->data;
315                 cgp = cg->priv;
316
317                 hwmon = g_string_sized_new(64);
318                 g_string_append_printf(hwmon,
319                                 "/sys/class/hwmon/hwmon%d/update_interval",
320                                 cgp->hwmon_num);
321
322                 if (g_file_test(hwmon->str, G_FILE_TEST_EXISTS)) {
323                         fd = g_fopen(hwmon->str, "w");
324                         if (!fd) {
325                                 g_string_free(hwmon, TRUE);
326                                 continue;
327                         }
328
329                         g_fprintf(fd, "%" PRIu64 "\n", 1000 / samplerate);
330                         fclose(fd);
331                 }
332
333                 g_string_free(hwmon, TRUE);
334         }
335 }
336
337 SR_PRIV int bl_acme_get_shunt(const struct sr_channel_group *cg,
338                               uint64_t *shunt)
339 {
340         GString *path = g_string_sized_new(64);
341         gchar *contents;
342         int status, ret = SR_OK;
343         GError *err = NULL;
344
345         status = get_shunt_path(cg, path);
346         if (status != SR_OK) {
347                 ret = status;
348                 goto out;
349         }
350
351         status = g_file_get_contents(path->str, &contents, NULL, &err);
352         if (!status) {
353                 sr_err("Error reading shunt resistance: %s", err->message);
354                 ret = SR_ERR_IO;
355                 goto out;
356         }
357
358         *shunt = UOHM_TO_MOHM(strtol(contents, NULL, 10));
359
360 out:
361         g_string_free(path, TRUE);
362         return ret;
363 }
364
365 SR_PRIV int bl_acme_set_shunt(const struct sr_channel_group *cg, uint64_t shunt)
366 {
367         GString *path = g_string_sized_new(64);;
368         int status, ret = SR_OK;
369         FILE *fd;
370
371         status = get_shunt_path(cg, path);
372         if (status != SR_OK) {
373                 ret = status;
374                 goto out;
375         }
376
377         /*
378          * Can't use g_file_set_contents() here, as it calls open() with
379          * O_EXEC flag in a sysfs directory thus failing with EACCES.
380          */
381         fd = g_fopen(path->str, "w");
382         if (!fd) {
383                 sr_err("Error opening %s: %s", path->str, g_strerror(errno));
384                 ret = SR_ERR_IO;
385                 goto out;
386         }
387
388         g_fprintf(fd, "%" PRIu64 "\n", MOHM_TO_UOHM(shunt));
389         fclose(fd);
390
391 out:
392         g_string_free(path, TRUE);
393         return ret;
394 }
395
396 SR_PRIV int bl_acme_read_power_state(const struct sr_channel_group *cg,
397                                      gboolean *off)
398 {
399         struct channel_group_priv *cgp;
400         int val;
401
402         cgp = cg->priv;
403
404         if (!bl_acme_probe_has_pws(cg)) {
405                 sr_err("Probe has no power-switch");
406                 return SR_ERR_ARG;
407         }
408
409         val = sr_gpio_getval_export(pws_gpios[cgp->index]);
410         *off = val ? FALSE : TRUE;
411
412         return SR_OK;
413 }
414
415 SR_PRIV int bl_acme_set_power_off(const struct sr_channel_group *cg,
416                                   gboolean off)
417 {
418         struct channel_group_priv *cgp;
419         int val;
420
421         cgp = cg->priv;
422
423         if (!bl_acme_probe_has_pws(cg)) {
424                 sr_err("Probe has no power-switch");
425                 return SR_ERR_ARG;
426         }
427
428         val = sr_gpio_setval_export(pws_gpios[cgp->index], off ? 0 : 1);
429         if (val < 0) {
430                 sr_err("Error setting power-off state: gpio: %d",
431                        pws_gpios[cgp->index]);
432                 return SR_ERR_IO;
433         }
434
435         return SR_OK;
436 }
437
438 static int channel_to_mq(struct sr_channel *ch)
439 {
440         struct channel_priv *chp;
441
442         chp = ch->priv;
443
444         switch (chp->ch_type) {
445         case ENRG_PWR:
446                 return SR_MQ_POWER;
447         case ENRG_CURR:
448                 return SR_MQ_CURRENT;
449         case ENRG_VOL:
450                 return SR_MQ_VOLTAGE;
451         case TEMP_IN: /* Fallthrough */
452         case TEMP_OUT:
453                 return SR_MQ_TEMPERATURE;
454         default:
455                 return -1;
456         }
457 }
458
459 static int channel_to_unit(struct sr_channel *ch)
460 {
461         struct channel_priv *chp;
462
463         chp = ch->priv;
464
465         switch (chp->ch_type) {
466         case ENRG_PWR:
467                 return SR_UNIT_WATT;
468         case ENRG_CURR:
469                 return SR_UNIT_AMPERE;
470         case ENRG_VOL:
471                 return SR_UNIT_VOLT;
472         case TEMP_IN: /* Fallthrough */
473         case TEMP_OUT:
474                 return SR_UNIT_CELSIUS;
475         default:
476                 return -1;
477         }
478 }
479
480 /* We need to scale measurements down from the units used by the drivers. */
481 static float adjust_data(int val, int type)
482 {
483         switch (type) {
484         case ENRG_PWR:
485                 return ((float)val) / 1000000.0;
486         case ENRG_CURR: /* Fallthrough */
487         case ENRG_VOL: /* Fallthrough */
488         case TEMP_IN: /* Fallthrough */
489         case TEMP_OUT:
490                 return ((float)val) / 1000.0;
491         default:
492                 return 0.0;
493         }
494 }
495
496 static float read_sample(struct sr_channel *ch)
497 {
498         struct channel_priv *chp;
499         char buf[16];
500         ssize_t len;
501         int fd;
502
503         chp = ch->priv;
504         fd = chp->fd;
505
506         lseek(fd, 0, SEEK_SET);
507
508         len = read(fd, buf, sizeof(buf));
509         if (len < 0) {
510                 sr_err("Error reading from channel %s (hwmon: %d): %s",
511                         ch->name, chp->probe->hwmon_num, g_strerror(errno));
512                 ch->enabled = FALSE;
513                 return -1.0;
514         }
515
516         return adjust_data(strtol(buf, NULL, 10), chp->ch_type);
517 }
518
519 SR_PRIV int bl_acme_open_channel(struct sr_channel *ch)
520 {
521         struct channel_priv *chp;
522         char path[64], *file;
523         int fd;
524
525         chp = ch->priv;
526
527         switch (chp->ch_type) {
528         case ENRG_PWR:  file = "power1_input";  break;
529         case ENRG_CURR: file = "curr1_input";   break;
530         case ENRG_VOL:  file = "in1_input";     break;
531         case TEMP_IN:   file = "temp1_input";   break;
532         case TEMP_OUT:  file = "temp2_input";   break;
533         default:
534                 sr_err("Invalid channel type: %d.", chp->ch_type);
535                 return SR_ERR;
536         }
537
538         snprintf(path, sizeof(path), "/sys/class/hwmon/hwmon%d/%s",
539                  chp->probe->hwmon_num, file);
540
541         fd = open(path, O_RDONLY);
542         if (fd < 0) {
543                 sr_err("Error opening %s: %s", path, g_strerror(errno));
544                 ch->enabled = FALSE;
545                 return SR_ERR;
546         }
547
548         chp->fd = fd;
549
550         return 0;
551 }
552
553 SR_PRIV void bl_acme_close_channel(struct sr_channel *ch)
554 {
555         struct channel_priv *chp;
556
557         chp = ch->priv;
558         close(chp->fd);
559         chp->fd = -1;
560 }
561
562 SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data)
563 {
564         uint32_t cur_time, elapsed_time;
565         uint64_t nrexpiration;
566         struct sr_datafeed_packet packet, framep;
567         struct sr_datafeed_analog analog;
568         struct sr_dev_inst *sdi;
569         struct sr_channel *ch;
570         struct channel_priv *chp;
571         struct dev_context *devc;
572         GSList *chl, chonly;
573         unsigned i;
574
575         (void)fd;
576         (void)revents;
577
578         sdi = cb_data;
579         if (!sdi)
580                 return TRUE;
581
582         devc = sdi->priv;
583         if (!devc)
584                 return TRUE;
585
586         packet.type = SR_DF_ANALOG;
587         packet.payload = &analog;
588         memset(&analog, 0, sizeof(struct sr_datafeed_analog));
589
590         if (read(devc->timer_fd, &nrexpiration, sizeof(nrexpiration)) < 0) {
591                 sr_warn("Failed to read timer information");
592                 return TRUE;
593         }
594
595         /*
596          * We were not able to process the previous timer expiration, we are
597          * overloaded.
598          */
599         if (nrexpiration > 1)
600                 devc->samples_missed += nrexpiration - 1;
601
602         /*
603          * XXX This is a nasty workaround...
604          *
605          * At high sampling rates and maximum channels we are not able to
606          * acquire samples fast enough, even though frontends still think
607          * that samples arrive on time. This causes shifts in frontend
608          * plots.
609          *
610          * To compensate for the delay we check if any clock events were
611          * missed and - if so - don't really read the next value, but send
612          * the same sample as fast as possible. We do it until we are back
613          * on schedule.
614          *
615          * At high sampling rate this doesn't seem to visibly reduce the
616          * accuracy.
617          */
618         for (i = 0; i < nrexpiration; i++) {
619                 framep.type = SR_DF_FRAME_BEGIN;
620                 sr_session_send(cb_data, &framep);
621
622                 /*
623                  * Due to different units used in each channel we're sending
624                  * samples one-by-one.
625                  */
626                 for (chl = sdi->channels; chl; chl = chl->next) {
627                         ch = chl->data;
628                         chp = ch->priv;
629
630                         if (!ch->enabled)
631                                 continue;
632                         chonly.next = NULL;
633                         chonly.data = ch;
634                         analog.channels = &chonly;
635                         analog.num_samples = 1;
636                         analog.mq = channel_to_mq(chl->data);
637                         analog.unit = channel_to_unit(ch);
638
639                         if (i < 1)
640                                 chp->val = read_sample(ch);
641
642                         analog.data = &chp->val;
643                         sr_session_send(cb_data, &packet);
644                 }
645
646                 framep.type = SR_DF_FRAME_END;
647                 sr_session_send(cb_data, &framep);
648         }
649
650         devc->samples_read++;
651         if (devc->limit_samples > 0 &&
652             devc->samples_read >= devc->limit_samples) {
653                 sr_info("Requested number of samples reached.");
654                 sdi->driver->dev_acquisition_stop(sdi, cb_data);
655                 devc->last_sample_fin = g_get_monotonic_time();
656                 return TRUE;
657         } else if (devc->limit_msec > 0) {
658                 cur_time = g_get_monotonic_time();
659                 elapsed_time = cur_time - devc->start_time;
660
661                 if (elapsed_time >= devc->limit_msec) {
662                         sr_info("Sampling time limit reached.");
663                         sdi->driver->dev_acquisition_stop(sdi, cb_data);
664                         devc->last_sample_fin = g_get_monotonic_time();
665                         return TRUE;
666                 }
667         }
668
669         devc->last_sample_fin = g_get_monotonic_time();
670         return TRUE;
671 }