Date:2010-08-25 11:40:03 (9 years 23 days ago)
Author:Werner Almesberger
Commit:4d49921b9be94ffdd05ffdb3827cb1193b46ebe0
Message:Added user-space counter utility.

- cntr/tools/Makefile: the usual recursive Makefile
- cntr/tools/cntr/Makefile, cntr/tools/cntr/cntr.c: user-space tool to
periodically read the free-running counter and to calculate frequency
and deviation from it
Files: cntr/tools/Makefile (1 diff)
cntr/tools/cntr/Makefile (1 diff)
cntr/tools/cntr/cntr.c (1 diff)

Change Details

cntr/tools/Makefile
1#
2# tools/Makefile - Build the ATSPI-specific tools
3#
4# Written 2010 by Werner Almesberger
5# Copyright 2010 Werner Almesberger
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12
13
14DIRS=cntr
15
16include ../../Makefile.recurse
cntr/tools/cntr/Makefile
1#
2# cntr/Makefile - Build the CNTR control tool
3#
4# Written 2010 by Werner Almesberger
5# Copyright 2010 Werner Almesberger
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12
13
14F32XBASE = ../../../../f32xbase
15
16MAIN = cntr
17OBJS += $(F32XBASE)/lib/usb.o
18
19include $(F32XBASE)/lib/Makefile.common
20
21CFLAGS += -I$(F32XBASE)/include -I../../fw/include -I../include
cntr/tools/cntr/cntr.c
1/*
2 * cntr/cntr.c - CNTR control tool
3 *
4 * Written 2010 by Werner Almesberger
5 * Copyright 2010 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13
14#include <stdlib.h>
15#include <stdio.h>
16#include <usb.h>
17#include <sys/time.h>
18
19#include "f32xbase/usb.h"
20#include "cntr/ep0.h"
21#include "cntr/usb-ids.h"
22
23
24#define FROM_DEV CNTR_FROM_DEV(0)
25#define TO_DEV CNTR_TO_DEV(0)
26
27#define DEFAULT_CLOCK_DEV_S 0.1 /* 100 ms, typ. NTP over WLAN dev. */
28#define BUF_SIZE 256
29
30
31
32static void reset_cntr(usb_dev_handle *dev)
33{
34    int res;
35
36    res = usb_control_msg(dev, TO_DEV, CNTR_RESET, 0, 0, NULL, 0, 1000);
37    if (res < 0) {
38        fprintf(stderr, "CNTR_RESET: %d\n", res);
39        exit(1);
40    }
41}
42
43
44static void identify_cntr(usb_dev_handle *dev)
45{
46    const struct usb_device *device = usb_device(dev);
47    uint8_t ids[3];
48    char buf[BUF_SIZE+1]; /* +1 for terminating \0 */
49    int res;
50
51    printf("%04x:%04x ",
52        device->descriptor.idVendor, device->descriptor.idProduct);
53
54    res = usb_control_msg(dev, FROM_DEV, CNTR_ID, 0, 0,
55        (char *) ids, sizeof(ids), 1000);
56    if (res < 0) {
57        fprintf(stderr, "CNTR_ID: %s\n", usb_strerror());
58        exit(1);
59    }
60
61    printf("protocol %u.%u hw %u\n", ids[0], ids[1], ids[2]);
62
63    res = usb_control_msg(dev, FROM_DEV, CNTR_BUILD, 0, 0,
64        buf, sizeof(buf), 1000);
65    if (res < 0) {
66        fprintf(stderr, "CNTR_BUILD: %s\n", usb_strerror());
67        exit(1);
68    }
69    buf[res] = 0;
70    printf("%10s%s\n", "", buf);
71}
72
73
74struct sample {
75    double t0, t1;
76    uint64_t cntr;
77};
78
79
80static void get_sample(usb_dev_handle *dev, struct sample *s)
81{
82    static uint32_t last = 0, high = 0;
83    struct timeval t0, t1;
84    int res;
85    uint8_t buf[4];
86    uint32_t cntr;
87
88    gettimeofday(&t0, NULL);
89    res = usb_control_msg(dev, FROM_DEV, CNTR_READ, 0, 0,
90        (char *) buf, sizeof(buf), 1000);
91    gettimeofday(&t1, NULL);
92    if (res < 0) {
93        fprintf(stderr, "CNTR_READ: %s\n", usb_strerror());
94        exit(1);
95    }
96    cntr = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
97    if (last > cntr)
98        high++;
99    last = cntr;
100    s->t0 = t0.tv_sec+t0.tv_usec/1000000.0;
101    s->t1 = t1.tv_sec+t1.tv_usec/1000000.0;
102    s->cntr = (uint64_t) high << 32 | cntr;
103}
104
105
106static void measure(usb_dev_handle *dev, double clock_dev_s)
107{
108    struct sample start, now;
109    uint64_t dc;
110    double dt, f, error;
111    char *f_exp, error_exp;
112
113    get_sample(dev, &start);
114    while (1) {
115        usleep(100000);
116        get_sample(dev, &now);
117        dc = now.cntr-start.cntr;
118        dt = now.t0-start.t0;
119        f = dc/dt;
120        if (f > 1000000.0) {
121            f /= 1000000.0;
122            f_exp = "M";
123        } else if (f > 1000.0) {
124            f /= 1000.0;
125            f_exp = "k";
126        } else {
127            f_exp = "";
128        }
129        if (dc)
130            error = 1.0/dc; /* one count */
131        else
132            error = 0;
133        error += (start.t1-start.t0)/dt;/* start sample read */
134        error += (now.t1-now.t0)/dt; /* last sample read */
135        error += clock_dev_s/dt; /* system clock deviation */
136        if (error > 1) {
137            printf("\r(wait) ");
138            fflush(stdout);
139            continue;
140        }
141
142        error_exp = 'k';
143        error *= 1000.0; /* ppm */
144        if (error < 1.0) {
145            error_exp = 'm'; /* ppm */
146            error *= 1000.0;
147        }
148        if (error < 1.0) {
149            error_exp = 'b'; /* ppb */
150            error *= 1000.0;
151        }
152
153        printf("\r%6.1f %1.9f %sHz %3.3f pp%c ",
154            dt, f, f_exp, error, error_exp);
155        fflush(stdout);
156    }
157}
158
159
160static void usage(const char *name)
161{
162    fprintf(stderr,
163"usage: %s [clock_dev_s]\n"
164"%6s %s -i\n"
165"%6s %s r\n\n"
166" clock_dev_s is the maximum deviation of the system clock, in seconds\n"
167" (default: %g s)\n"
168" -i identify the CNTR board\n"
169" -r reset the CNTR board\n"
170    , name, "", name, "", name, DEFAULT_CLOCK_DEV_S);
171    exit(1);
172}
173
174
175int main(int argc, char *const *argv)
176{
177    usb_dev_handle *dev;
178    int c, identify = 0, reset = 0;
179    double clock_dev_s = DEFAULT_CLOCK_DEV_S;
180    char *end;
181
182    while ((c = getopt(argc, argv, "ir")) != EOF)
183        switch (c) {
184        case 'i':
185            identify = 1;
186            break;
187        case 'r':
188            reset = 1;
189            break;
190        default:
191            usage(*argv);
192        }
193
194    switch (argc-optind) {
195    case 0:
196        break;
197    case 1:
198        clock_dev_s = strtod(argv[optind], &end);
199        if (*end)
200            usage(*argv);
201        break;
202    default:
203        usage(*argv);
204    }
205
206    dev = open_usb(USB_VENDOR, USB_PRODUCT);
207    if (!dev) {
208        fprintf(stderr, ":-(\n");
209        return 1;
210    }
211
212    if (identify) {
213        identify_cntr(dev);
214        return 0;
215    }
216
217    if (reset) {
218        reset_cntr(dev);
219        return 0;
220    }
221
222    measure(dev, clock_dev_s);
223
224    return 0;
225}

Archive Download the corresponding diff file



interactive