r4076 - in developers/werner: . ahrt ahrt/host ahrt/host/scpinet ahrt/host/usbtmc ahrt/lang ahrt/lang/scpi ahrt/layout ahrt/target ahrt/target/wkalrm
werner at sita.openmoko.org
werner at sita.openmoko.org
Sat Feb 16 13:27:25 CET 2008
Author: werner
Date: 2008-02-16 13:27:13 +0100 (Sat, 16 Feb 2008)
New Revision: 4076
Added:
developers/werner/ahrt/
developers/werner/ahrt/README
developers/werner/ahrt/host/
developers/werner/ahrt/host/scpinet/
developers/werner/ahrt/host/scpinet/Makefile
developers/werner/ahrt/host/scpinet/README
developers/werner/ahrt/host/scpinet/scpinet.c
developers/werner/ahrt/host/usbtmc/
developers/werner/ahrt/host/usbtmc/Makefile
developers/werner/ahrt/host/usbtmc/README
developers/werner/ahrt/host/usbtmc/usbtmc.c
developers/werner/ahrt/lang/
developers/werner/ahrt/lang/manual/
developers/werner/ahrt/lang/scpi/
developers/werner/ahrt/lang/scpi/mamps
developers/werner/ahrt/lang/scpi/setup
developers/werner/ahrt/layout/
developers/werner/ahrt/layout/werner
developers/werner/ahrt/target/
developers/werner/ahrt/target/gpio/
developers/werner/ahrt/target/wkalrm/
developers/werner/ahrt/target/wkalrm/Makefile
developers/werner/ahrt/target/wkalrm/README
developers/werner/ahrt/target/wkalrm/wkalrm.c
Log:
Infrastructure for automated hardware regression tests. Work in progress.
Added: developers/werner/ahrt/README
===================================================================
--- developers/werner/ahrt/README 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/README 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,2 @@
+Automated Hardware Regression Tests
+===================================
Added: developers/werner/ahrt/host/scpinet/Makefile
===================================================================
--- developers/werner/ahrt/host/scpinet/Makefile 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/host/scpinet/Makefile 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,20 @@
+CFLAGS=-Wall -O
+LDFLAGS=-g
+
+PREFIX=/usr
+
+.PHONY: all install uninstall clean spotless
+
+all: scpinet
+
+install: all
+ install -D scpinet $(PREFIX)/bin/scpinet
+
+uninstall:
+ rm -f $(PREFIX)/bin/scpinet
+
+clean:
+ rm -f scpinet.o
+
+spotless: clean
+ rm -f scpinet
Added: developers/werner/ahrt/host/scpinet/README
===================================================================
--- developers/werner/ahrt/host/scpinet/README 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/host/scpinet/README 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,56 @@
+scpinet - Send SCPI commands to a device that supports TELNET access
+====================================================================
+
+Copyright (C) 2008 by OpenMoko, Inc.
+Written by Werner Almesberger <werner at openmoko.org>
+All Rights Reserved
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+
+scpinet is a user-space utility that talks to SCPI devices that support
+TELNET access, such as the Fluke 8845A.
+
+
+Usage
+-----
+
+scpinet [options] host command ...
+
+
+Each command is an SCPI command string. If the command contains spaces or
+other shell meta-characters, it has to be quoted. If a command contains a
+question mark, "scpinet" will retrieve a reponse from the device after
+sending the command.
+
+The host name or address must always be specified. The port defaults to
+3490 and can be changed with the option "-p port".
+
+The option "-t tries" sets the number of times scpinet will try to connect
+to a device returning "connection refused" or "connection reset by peet"
+before giving up. The default is one try. "-t 0" sets an unlimited number
+of tries. scpinet pauses for one second between successive tries.
+
+Reponses normally end with a newline. This can be suppressed with the
+option -n.
+
+
+Reconnect pause
+---------------
+
+The Fluke 8845A accepts only one session at a time, and needs a brief
+pause between sessions. Attempts to connect too quickly yield "connection
+refused". Also, sometimes the connection gets reset when trying to read
+a result from the device.
+
+This can be worked around by setting the option "-t 3".
+
+
+Known problems and missing features
+-----------------------------------
+
+Question marks in quoted strings will fool the heuristics that detect when
+a response is expected.
Added: developers/werner/ahrt/host/scpinet/scpinet.c
===================================================================
--- developers/werner/ahrt/host/scpinet/scpinet.c 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/host/scpinet/scpinet.c 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,226 @@
+/*
+ * scpinet.c - Send SCPI commands to a device that supports TELNET access
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#define DEFAULT_PORT "3490"
+#define DEFAULT_TRIES 1
+
+
+static int max_tries = DEFAULT_TRIES;
+static int tries_left;
+
+
+static int tcp_open(const char *host, const char *port)
+{
+ struct sockaddr_in addr;
+ const struct hostent *he;
+ const struct servent *se;
+ unsigned long num;
+ char *end;
+ int s;
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(host);
+ if (addr.sin_addr.s_addr == INADDR_NONE) {
+ he = gethostbyname(host);
+ if (!he) {
+ fprintf(stderr, "unknown host \"%s\"\n", host);
+ exit(1);
+ }
+ addr.sin_addr = *(struct in_addr *) he->h_addr;
+ }
+
+ se = getservbyname(port, "tcp");
+ if (se)
+ addr.sin_port = se->s_port;
+ else {
+ num = strtoul(port, &end, 0);
+ if (!num || num > 0xffff || *end) {
+ fprintf(stderr, "invalid port \"%s\"\n", port);
+ exit(1);
+ }
+ addr.sin_port = htons(num);
+ }
+
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(1);
+ }
+
+ tries_left = max_tries;
+ while (1) {
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) >= 0)
+ return s;
+ if (errno != ECONNREFUSED || tries_left == 1) {
+ perror("connect");
+ exit(1);
+ }
+ if (tries_left)
+ tries_left--;
+ sleep(1);
+ }
+}
+
+
+static void tcp_write(int s, const void *buf)
+{
+ size_t len = strlen(buf);
+ ssize_t wrote;
+
+ while (len) {
+ wrote = write(s, buf, len);
+ if (wrote < 0) {
+ perror("write");
+ exit(1);
+ }
+ if (!wrote) {
+ fprintf(stderr, "write: wrote 0 bytes\n");
+ exit(1);
+ }
+ buf += wrote;
+ len -= wrote;
+ }
+}
+
+
+static ssize_t tcp_read(int s, void *buf, size_t size)
+{
+ size_t total = 0;
+ ssize_t got;
+ int crlf = 0;
+ char *p;
+
+ do {
+ got = read(s, buf, size-total);
+ if (got < 0 && errno == ECONNRESET &&
+ (tries_left || !max_tries))
+ return got;
+ if (got < 0) {
+ perror("read");
+ exit(1);
+ }
+ if (!got) {
+ fprintf(stderr, "read: unexpected EOF\n");
+ exit(1);
+ }
+ for (p = buf; p != buf+got; p++)
+ switch (*p) {
+ case '\r':
+ if (crlf)
+ fprintf(stderr,
+ "warning: unexpected \\r\n");
+ crlf = 1;
+ break;
+ case '\n':
+ if (crlf != 1)
+ fprintf(stderr,
+ "warning: unexpected \\n\n");
+ crlf = 2;
+ break;
+ default:
+ if (crlf)
+ fprintf(stderr,
+ "warning: data after \\r\\n\n");
+ crlf = 0;
+ break;
+ }
+ buf += got;
+ total += got;
+ }
+ while (crlf != 2);
+ return total-2;
+}
+
+
+static void usage(const char *name)
+{
+ fprintf(stderr,
+"usage: %s [-n] [-t max_tries] [-p port] host command ...\n"
+" -n do not end reponses with a newline\n"
+" -p port connect to the specified TCP port (default: %s)\n"
+" -t max_tries try to connect up to the specified number of times.\n"
+" 0 tries forever. (default: %d)\n"
+ , name, DEFAULT_PORT, DEFAULT_TRIES);
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ const char *port = DEFAULT_PORT;
+ char *end;
+ int nl = 1;
+ int c, s, i;
+
+ while ((c = getopt(argc, argv, "np:t:")) != EOF)
+ switch (c) {
+ case 'n':
+ nl = 0;
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 't':
+ max_tries = strtoul(optarg, &end, 0);
+ if (*end || max_tries < 0)
+ usage(*argv);
+ break;
+ default:
+ usage(*argv);
+ }
+
+ if (optind == argc)
+ usage(*argv);
+
+again:
+ s = tcp_open(argv[optind], port);
+
+ for (i = optind+1; i != argc; i++) {
+ tcp_write(s, argv[i]);
+ tcp_write(s, "\r\n");
+ if (strchr(argv[i], '?')) {
+ char buf[1024*1024]; /* be generous */
+ ssize_t got;
+
+ got = tcp_read(s, buf, sizeof(buf)-1);
+ if (got < 0) {
+ tries_left--;
+ close(s);
+ goto again;
+ }
+ buf[got] = 0;
+ printf("%s%s", buf, nl ? "\n" : "");
+ }
+ }
+
+ if (close(s) < 0) {
+ perror("close");
+ exit(1);
+ }
+
+ return 0;
+}
Added: developers/werner/ahrt/host/usbtmc/Makefile
===================================================================
--- developers/werner/ahrt/host/usbtmc/Makefile 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/host/usbtmc/Makefile 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,20 @@
+CFLAGS=-Wall -O
+LDFLAGS=-g -lusb
+
+PREFIX=/usr
+
+.PHONY: all install uninstall clean spotless
+
+all: usbtmc
+
+install: all
+ install -D usbtmc $(PREFIX)/bin/usbtmc
+
+uninstall:
+ rm -f $(PREFIX)/bin/usbtmc
+
+clean:
+ rm -f usbtmc.o
+
+spotless: clean
+ rm -f usbtmc
Added: developers/werner/ahrt/host/usbtmc/README
===================================================================
--- developers/werner/ahrt/host/usbtmc/README 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/host/usbtmc/README 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,97 @@
+usbtmc - A basic implementation of the USBTMC protocol
+======================================================
+
+Copyright (C) 2008 by OpenMoko, Inc.
+Written by Werner Almesberger <werner at openmoko.org>
+All Rights Reserved
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+
+usbtmc is a user-space utility that implements enough of the USBTMC
+protocol to talk to a PicoTest M3500A on a good day.
+
+This driver is based on the Agilent USBTMC kernel driver by Stefan Kopp:
+http://www.home.agilent.com/upload/cmc_upload/All/usbtmc.html
+http://www.home.agilent.com/upload/cmc_upload/All/usbtmc.tar
+
+In order to lower the barrier for deployment, usbtmc uses libusb and
+does thus not require any kernel changes.
+
+
+Usage
+-----
+
+usbtmc [options] command ...
+
+
+Each command is an SCPI command string. If the command contains spaces or
+other shell meta-characters, it has to be quoted. If a command contains a
+question mark, "usbtmc" will retrieve a reponse from the device after
+sending the command.
+
+
+The following options select which USBTMC device to talk to:
+
+"-v vendor_id" and "-p product_id" restrict the USB vendor and product ID
+of the device. "-b bus_number" and "-d device_number" restrict the USB
+bus number and the (logical) device number.
+
+By default, any USBTMC device will be selected. If more than one device
+is found, "usbtmc" will report an error and exit.
+
+
+The option "-t seconds" sets a timeout for responses. If the timeout is
+exceeded, usbtmc will print and error and exit. This can be changed with
+the option -r, which makes usbtmc resend the last command and wait again
+for a response.
+
+By default, usbtmc waits forever for a response.
+
+
+Reponses normally end with a newline. This can be suppressed with the
+option -n. Note that this applies to all responses. E.g.,
+
+usbtmc -n 'DISP:TEXT "foo"' 'DISP:TEXT?' 'DISP:TEXT?'
+
+will yield
+
+"foo""foo"
+
+
+The option -D enabled debugging output.
+
+
+Data copy bug
+-------------
+
+At least in firmware revision 02.03-01-04 of the PicoTest M3500A, there
+seems to be a bug that sometimes causes data not to be copied into the
+output buffer.
+
+This does not seem to be related to the timing of the respective USB
+transactions. Executing commands does not seem to be affected, e.g., a
+loop of SYST:BEEP will not have pauses.
+
+As a work-around, we have the option -r that retries the entire command
+sequence if a timeout occurs.
+
+
+Known problems and missing features
+-----------------------------------
+
+Only a small part of the error recovery procedures required by USBTMC are
+implemented. More of this will be added later.
+
+usbtmc hasn't been tested yet with operations that take a while to complete.
+Timeouts are expected to get in the way there.
+
+The USBTMC specification seems a bit unclear about the treatment of bTag,
+so it may be that just starting with 1 in each session actually violates
+the protocol.
+
+Question marks in quoted strings will fool the heuristics that detect when
+a response is expected.
Added: developers/werner/ahrt/host/usbtmc/usbtmc.c
===================================================================
--- developers/werner/ahrt/host/usbtmc/usbtmc.c 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/host/usbtmc/usbtmc.c 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,521 @@
+/*
+ * usbtmc.c - Partial implementation of the Universal Serial Bus Test and
+ * Measurement Class Specification (USBTMC)
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Based on the Agilent USBTMC kernel driver by Stefan Kopp:
+ * http://www.home.agilent.com/upload/cmc_upload/All/usbtmc.html
+ * http://www.home.agilent.com/upload/cmc_upload/All/usbtmc.tar
+ */
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#include <usb.h>
+
+
+#ifndef USB_CLASS_APP_SPEC
+#define USB_CLASS_APP_SPEC 0xfe
+#endif
+
+#ifndef USB_SUBCLASS_USBTMC
+#define USB_SUBCLASS_USBTMC 0x03
+#endif
+
+#ifndef USB_PROTOCOL_USB488
+#define USB_PROTOCOL_USB488 1
+#endif
+
+#define SIZE_IOBUFFER 4096
+#define DEV_DEP_MSG_OUT 1
+#define DEV_DEP_MSG_IN 2
+#define INITIATE_ABORT_BULK_IN 3
+
+
+static uint8_t ep_int_in, ep_bulk_in, ep_bulk_out;
+static uint8_t bTag;
+static int debug = 0, timeout = 0;
+
+
+/* ----- Debugging --------------------------------------------------------- */
+
+
+static void dump(const char *label, void *data, size_t size)
+{
+ int i;
+
+ if (!debug)
+ return;
+ fprintf(stderr, "%s (%d)", label, (int) size);
+ for (i = 0; i != size; i++) {
+ if (!(i & 15))
+ fprintf(stderr, "\n%04x ", i);
+ fprintf(stderr, " %02x", ((uint8_t *) data)[i]);
+ }
+ fprintf(stderr, "\n");
+}
+
+
+/* ----- Device selection -------------------------------------------------- */
+
+
+static void multiple_ep(const char *type)
+{
+ fprintf(stderr,
+ "multiple %s endpoints found\n", type);
+ exit(1);
+}
+
+
+static void multiple_dev(void)
+{
+ fprintf(stderr,
+ "multiple devices found. Please add more qualifiers\n");
+ exit(1);
+}
+
+
+static void get_eps(const struct usb_interface_descriptor *alt)
+{
+ const struct usb_endpoint_descriptor *ep;
+ uint8_t type_dir;
+
+ for (ep = alt->endpoint;
+ ep != alt->endpoint+alt->bNumEndpoints;
+ ep++) {
+ type_dir = (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK) |
+ (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK);
+ switch (type_dir) {
+ case USB_ENDPOINT_TYPE_INTERRUPT | USB_ENDPOINT_IN:
+ if (ep_int_in)
+ multiple_ep("Interrupt-IN");
+ ep_int_in = ep->bEndpointAddress;
+ break;
+ case USB_ENDPOINT_TYPE_BULK | USB_ENDPOINT_IN:
+ if (ep_bulk_in)
+ multiple_ep("Bulk-IN");
+ ep_bulk_in = ep->bEndpointAddress;
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ if (ep_bulk_out)
+ multiple_ep("Bulk-OUT");
+ ep_bulk_out = ep->bEndpointAddress;
+ break;
+ default:
+ fprintf(stderr,
+ "endpoint type 0x%02x is not supported\n",
+ type_dir);
+ exit(1);
+ }
+ }
+}
+
+
+static usb_dev_handle *open_usbtmc_alt(struct usb_device *dev,
+ const struct usb_config_descriptor *cfg,
+ const struct usb_interface *itf,
+ struct usb_interface_descriptor *alt)
+{
+ usb_dev_handle *handle;
+ int error;
+
+ if (alt->bDescriptorType != USB_DT_INTERFACE)
+ return NULL;
+ if (alt->bAlternateSetting)
+ return NULL;
+ if (alt->bInterfaceClass != USB_CLASS_APP_SPEC)
+ return NULL;
+ if (alt->bInterfaceSubClass != USB_SUBCLASS_USBTMC)
+ return NULL;
+ if (alt->bInterfaceProtocol &&
+ alt->bInterfaceProtocol != USB_PROTOCOL_USB488)
+ return NULL;
+
+ handle = usb_open(dev);
+ if (!handle) {
+ fprintf(stderr, "cannot open device\n");
+ exit(1);
+ }
+ error = usb_set_configuration(handle, cfg->bConfigurationValue);
+ if (error) {
+ fprintf(stderr, "cannot set configuration (error %d)\n",
+ error);
+ exit(1);
+ }
+ error = usb_claim_interface(handle, alt->bInterfaceNumber);
+ if (error) {
+ fprintf(stderr, "cannot claim interface (error %d)\n", error);
+ exit(1);
+ }
+ error = usb_set_altinterface(handle, alt->bAlternateSetting);
+ if (error) {
+ fprintf(stderr, "cannot set alternate setting (error %d)\n",
+ error);
+ exit(1);
+ }
+
+ get_eps(alt);
+
+ /* amazingly enough, after all this searching, we have a device */
+ return handle;
+}
+
+
+static usb_dev_handle *open_usbtmc_dev(struct usb_device *dev)
+{
+ const struct usb_config_descriptor *cfg;
+ const struct usb_interface *itf;
+ struct usb_interface_descriptor *alt;
+ usb_dev_handle *found, *handle = NULL;
+
+ if (dev->descriptor.bDeviceClass ||
+ dev->descriptor.bDeviceSubClass ||
+ dev->descriptor.bDeviceProtocol)
+ return NULL;
+ /* seems that libusb doesn't provide the Device_Qualifier
+ descriptor, so we can't sanity-check that one */
+
+ for (cfg = dev->config;
+ cfg != dev->config+dev->descriptor.bNumConfigurations;
+ cfg++)
+ for (itf = cfg->interface;
+ itf != cfg->interface+cfg->bNumInterfaces;
+ itf++)
+ for (alt = itf->altsetting;
+ alt != itf->altsetting+itf->num_altsetting;
+ alt++) {
+ found = open_usbtmc_alt(dev, cfg, itf, alt);
+ if (!found)
+ continue;
+ if (handle)
+ multiple_dev();
+ handle = found;
+ }
+ return handle;
+}
+
+
+static usb_dev_handle *open_usbtmc(uint16_t vendor, uint16_t product,
+ uint8_t bus_id, uint8_t dev_id)
+{
+ const struct usb_bus *bus;
+ struct usb_device *dev;
+ usb_dev_handle *found, *handle = NULL;;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_get_busses(); bus; bus = bus->next) {
+ if (bus_id && atoi(bus->dirname) != bus_id)
+ continue;
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if (dev_id && dev->devnum != dev_id)
+ continue;
+ if (vendor && dev->descriptor.idVendor != vendor)
+ continue;
+ if (product && dev->descriptor.idProduct != product)
+ continue;
+ found = open_usbtmc_dev(dev);
+ if (!found)
+ continue;
+ if (debug)
+ fprintf(stderr,
+ "USBTMC device %04X:%04X at %s/%s\n",
+ dev->descriptor.idVendor,
+ dev->descriptor.idProduct,
+ bus->dirname, dev->filename);
+
+ if (handle)
+ multiple_dev();
+ handle = found;
+ }
+ }
+ return handle;
+}
+
+
+/* ----- USBTMC Communication ---------------------------------------------- */
+
+
+static void usbtmc_abort_in(usb_dev_handle *handle)
+{
+ uint8_t buf[2];
+ ssize_t got;
+
+ got = usb_control_msg(handle,
+ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
+ INITIATE_ABORT_BULK_IN,
+ bTag,
+ ep_bulk_in,
+ (void *) buf, 2, timeout);
+ if (got < 0) {
+ fprintf(stderr, "INITIATE_ABORT_BULK_IN error %d\n",
+ (int) got);
+ return;
+ }
+ fprintf(stderr, "status 0x%02x bTag 0x%02x\n", buf[0], buf[1]);
+
+ /* depending on status, do more */
+}
+
+
+static void usbtmc_write(usb_dev_handle *handle, char *msg)
+{
+ uint8_t buf[SIZE_IOBUFFER];
+ size_t left, size, send_size;
+ ssize_t sent;
+
+ memset(buf, 0, sizeof(buf));
+
+ for (left = strlen(msg); left; left -= size) {
+ buf[8] = left <= SIZE_IOBUFFER-12;
+ size = buf[8] ? left : SIZE_IOBUFFER-12;
+
+ bTag++;
+ buf[0] = DEV_DEP_MSG_OUT;
+ buf[1] = bTag;
+ buf[2] = ~bTag;
+ buf[4] = size;
+ buf[5] = size >> 8;
+ buf[6] = size >> 16;
+ buf[7] = size >> 24;
+
+ memcpy(buf+12, msg, size);
+ msg += size;
+
+ send_size = 12+((size+3) & ~3);
+
+ dump("SEND: DEV_DEP_MSG_OUT", buf, send_size);
+ sent = usb_bulk_write(handle, ep_bulk_out, (void *) buf,
+ send_size, timeout);
+ if (sent < 0) {
+ fprintf(stderr, "write error %d\n", (int) sent);
+ exit(1);
+ }
+ if (sent != send_size) {
+ fprintf(stderr, "sent %d instead of %d bytes\n",
+ (int) sent, (int) send_size);
+ exit(1);
+ }
+ }
+}
+
+
+static size_t usbtmc_read(usb_dev_handle *handle, char *msg, size_t length)
+{
+ uint8_t buf[SIZE_IOBUFFER];
+ size_t left, size;
+ ssize_t sent, got;
+ uint32_t payload;
+
+ for (left = length; left; left -= got) {
+ memset(buf, 0, sizeof(buf));
+
+ size = SIZE_IOBUFFER-12;
+ if (size > left)
+ size = left;
+
+ bTag++;
+ buf[0] = DEV_DEP_MSG_IN;
+ buf[1] = bTag;
+ buf[2] = ~bTag;
+ buf[4] = size;
+ buf[5] = size >> 8;
+ buf[6] = size >> 16;
+ buf[7] = size >> 24;
+
+ dump("SEND: DEV_DEP_MSG_IN", buf, 12);
+ sent =
+ usb_bulk_write(handle, ep_bulk_out, (void *) buf, 12,
+ timeout);
+ if (sent < 0) {
+ fprintf(stderr, "write error %d\n", (int) sent);
+ exit(1);
+ }
+ if (sent != 12) {
+ fprintf(stderr, "sent %d instead of 12 bytes\n",
+ (int) sent);
+ exit(1);
+ }
+
+ got = usb_bulk_read(handle, ep_bulk_in, (void *) buf, size,
+ timeout);
+ if (got < 0) {
+ usbtmc_abort_in(handle);
+ fprintf(stderr, "read error %d\n", (int) got);
+ return got;
+ }
+ dump("RECV: DEV_DEP_MSG_IN", buf, got);
+ if (got < 12) {
+ /* ABORT */
+ fprintf(stderr,
+ "received %d bytes, need at least 12\n", (int) got);
+ exit(1);
+ }
+ if (got > size) {
+ /* ABORT */
+ fprintf(stderr,
+ "received %d bytes, wanted no more than %d\n",
+ (int) got, (int) size);
+ exit(1);
+ }
+
+ if (buf[0] != DEV_DEP_MSG_IN) {
+ /* ABORT */
+ fprintf(stderr, "unexpected message type 0x%02x\n",
+ buf[0]);
+ exit(1);
+ }
+ if (buf[1] != bTag || buf[2] != (~bTag & 0xff)) {
+ /* ABORT */
+ fprintf(stderr,
+ "received bTag 0x%02x/0x%02x, "
+ "expected 0x%02x/0x%02x\n",
+ buf[1], buf[2], bTag, ~bTag & 0xff);
+ exit(1);
+ }
+
+ if (buf[8] & 2) {
+ fprintf(stderr, "unexpected TermChar\n");
+ exit(1);
+ }
+
+ payload =
+ buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
+ if (!payload) {
+ fprintf(stderr,
+ "zero-length DEV_DEP_MSG_IN payload\n");
+ exit(1);
+ }
+ if (payload > size) {
+ fprintf(stderr,
+ "DEV_DEP_MSG_IN payload has %lu bytes, "
+ "we have space for %d\n",
+ (unsigned long) payload, (int) size);
+ exit(1);
+ }
+
+ memcpy(msg, buf+12, payload);
+ msg += payload;
+ left -= payload;
+
+ if (buf[8] & 1)
+ break;
+ }
+ return length-left;
+}
+
+
+/* ----- Main -------------------------------------------------------------- */
+
+
+static void usage(const char *name)
+{
+ fprintf(stderr,
+"usage: %s [-D] [-r] [-n] [-f] [-t timeout] [-v vendor_id]\n"
+" %*s [-p product_id] [-b bus_number] [-d device_number] command ...\n\n"
+" -b bus_number USB bus number (8 bit)\n"
+" -d device_number USB device number (8 bit)\n"
+" -D enable debug output\n"
+" -n do not end reponses with a newline\n"
+" -p product_id USB product identifier (16 bit)\n"
+" -r retry after an input timeout\n"
+" -t seconds timeout per USB operation (default: infinite)\n"
+" -v vendor_id USB vendor identifier (16 bit)\n"
+ , name, (int) strlen(name), "");
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ usb_dev_handle *handle;
+ uint16_t vendor = 0, product = 0;
+ uint8_t bus = 0, device = 0;
+ int c, i;
+ char *end;
+ unsigned long tmp;
+ int nl = 1, retry = 0;
+
+ while ((c = getopt(argc, argv, "b:d:Dnp:rt:v:")) != EOF)
+ switch (c) {
+ case 'b':
+ tmp = strtoul(optarg, &end, 0);
+ if (*end || bus || !tmp || tmp > 0xff)
+ usage(*argv);
+ bus = tmp;
+ break;
+ case 'd':
+ tmp = strtoul(optarg, &end, 0);
+ if (*end || device || !tmp || tmp > 0xff)
+ usage(*argv);
+ device = tmp;
+ break;
+ case 'D':
+ debug = 1;
+ break;
+ case 'n':
+ nl = 0;
+ break;
+ case 'p':
+ tmp = strtoul(optarg, &end, 0);
+ if (*end || product || !tmp || tmp > 0xffff)
+ usage(*argv);
+ product = tmp;
+ break;
+ case 'r':
+ retry = 1;
+ break;
+ case 't':
+ tmp = strtoul(optarg, &end, 0);
+ if (*end || timeout || !tmp || tmp > INT_MAX/1000)
+ usage(*argv);
+ timeout = tmp*1000;
+ break;
+ case 'v':
+ tmp = strtoul(optarg, &end, 0);
+ if (*end || vendor || !tmp || tmp > 0xffff)
+ usage(*argv);
+ vendor = tmp;
+ break;
+ default:
+ usage(*argv);
+ }
+
+ handle = open_usbtmc(vendor, product, bus, device);
+ if (!handle) {
+ fprintf(stderr, "no device found\n");
+ return 1;
+ }
+
+ for (i = optind; i != argc; i++) {
+again:
+ usbtmc_write(handle, argv[i]);
+ if (strchr(argv[i], '?')) {
+ char buf[1024*1024]; /* be generous */
+ ssize_t got;
+
+ got = usbtmc_read(handle, buf, sizeof(buf)-1);
+ if (got < 0 && retry)
+ goto again;
+ buf[got] = 0;
+ printf("%s%s", buf, nl ? "\n" : "");
+ }
+ }
+
+ return 0;
+}
Added: developers/werner/ahrt/lang/scpi/mamps
===================================================================
--- developers/werner/ahrt/lang/scpi/mamps 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/lang/scpi/mamps 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,14 @@
+#
+# mamps - Measure amperes
+#
+# usage: mamps [maximum]
+#
+# Get a set of current measurements from the device.
+#
+
+q="CONF:CURR:DC"
+if [ ! -z "$1" ]; then
+ q="$q $1"
+fi
+$cmd '*CLS' "$q" 'CURR:DC:NPLC 1' 'TRIG:SOUR IMM' 'TRIG:DEL 0' 'TRIG:COUN 1' \
+ 'SAMP:COUN 20' 'INIT' 'FETCH?'
Property changes on: developers/werner/ahrt/lang/scpi/mamps
___________________________________________________________________
Name: svn:executable
+ *
Added: developers/werner/ahrt/lang/scpi/setup
===================================================================
--- developers/werner/ahrt/lang/scpi/setup 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/lang/scpi/setup 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,8 @@
+#
+# setup - Prepare the device for a session
+#
+# usage: setup label
+#
+# Displays "label" on the devices's display.
+#
+$cmd SYST:REM DISP:TEXT\ \""$1"\"
Property changes on: developers/werner/ahrt/lang/scpi/setup
___________________________________________________________________
Name: svn:executable
+ *
Added: developers/werner/ahrt/layout/werner
===================================================================
--- developers/werner/ahrt/layout/werner 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/layout/werner 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,39 @@
+#
+# layout/werner - Werner's home setup
+#
+
+# USB current is measured by a PicoTest M3500A, connected to host "lab".
+# Battery current is measured by a Fluke 8845A, named "fluke".
+# Both power supplies are manual.
+
+usb_meter()
+{
+ args=
+ for n in "$@"; do
+ args="$args '$n'"
+ done
+ ssh lab usbtmc -r -t 2 "$args"
+}
+
+usb_mlang=scpi
+
+usb_power()
+{
+ :
+}
+
+usb_plang=manual
+
+bat_meter()
+{
+ scpinet -t 3 fluke "$@"
+}
+
+bat_mlang=scpi
+
+bat_power()
+{
+ :
+}
+
+bat_plang=manual
Added: developers/werner/ahrt/target/wkalrm/Makefile
===================================================================
--- developers/werner/ahrt/target/wkalrm/Makefile 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/target/wkalrm/Makefile 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,22 @@
+CC=arm-angstrom-linux-gnueabi-gcc
+
+CFLAGS=-Wall -O -g
+LDFLAGS=
+
+PREFIX=/usr
+
+.PHONY: all install uninstall clean spotless
+
+all: wkalrm
+
+install: all
+ install -D wkalrm $PREFIX/bin/wkalrm
+
+uninstall:
+ rm -f $PREFIX/bin/wkalrm
+
+clean:
+ rm -f wkalrm.o
+
+spotless:
+ rm -f wkalrm
Added: developers/werner/ahrt/target/wkalrm/README
===================================================================
--- developers/werner/ahrt/target/wkalrm/README 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/target/wkalrm/README 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,34 @@
+wkalrm - Use the RTC alarm to wake us up
+========================================
+
+Copyright (C) 2008 by OpenMoko, Inc.
+Written by Werner Almesberger <werner at openmoko.org>
+All Rights Reserved
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+
+wkalrm reads and sets the alarm function of the RTC.
+
+
+Usage
+-----
+
+wkalrm [-d device]
+wkalrm [-d device] +Nunit
+
+By default, wkalrm uses /dev/rtc0. This can be changed with the option
+"-d device".
+
+The delta time is specified with a plus sign, followed by the number
+of units (an integer), and the unit. The following units are recognized:
+
+ Day: d, day, days
+ Hours: h, hour, hours
+ Minutes: m, min, mins
+ Seconds: s, sec, secs
+
+If invoked without a delta time, wkalrm prints the current alarm setting.
Added: developers/werner/ahrt/target/wkalrm/wkalrm.c
===================================================================
--- developers/werner/ahrt/target/wkalrm/wkalrm.c 2008-02-16 11:13:00 UTC (rev 4075)
+++ developers/werner/ahrt/target/wkalrm/wkalrm.c 2008-02-16 12:27:13 UTC (rev 4076)
@@ -0,0 +1,235 @@
+/*
+ * wkalrm.c - Use the RTC alarm to wake us up
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/rtc.h>
+
+
+#define DEFAULT_RTC "/dev/rtc0"
+
+
+static const char *device = DEFAULT_RTC;
+static int fd;
+
+
+/* ----- Low-level wrappers ------------------------------------------------ */
+
+
+static void read_alarm(struct rtc_wkalrm *alarm)
+{
+ int res;
+
+ res = ioctl(fd, RTC_WKALM_RD, alarm);
+ if (res < 0) {
+ perror("ioctl(RTC_WKALM_RD)");
+ exit(1);
+ }
+}
+
+
+static void read_time(struct rtc_time *tm)
+{
+ int res;
+
+ res = ioctl(fd, RTC_RD_TIME, tm);
+ if (res < 0) {
+ perror("ioctl(RTC_RD_TIME)");
+ exit(1);
+ }
+}
+
+
+static void write_alarm(const struct rtc_wkalrm *alarm)
+{
+ int res;
+
+ res = ioctl(fd, RTC_WKALM_SET, alarm);
+ if (res < 0) {
+ perror("ioctl(RTC_WKALM_SET)");
+ exit(1);
+ }
+}
+
+
+/* ----- Date conversions -------------------------------------------------- */
+
+
+static void show_alarm(void)
+{
+ struct rtc_wkalrm alarm;
+
+ read_alarm(&alarm);
+ if (!alarm.enabled)
+ printf("alarm disabled%s\n",
+ alarm.pending ? " (pending)" : "");
+ else
+ printf("%02d:%02d:%02d %04d-%02d-%02d%s\n",
+ alarm.time.tm_hour, alarm.time.tm_min, alarm.time.tm_sec,
+ alarm.time.tm_year+1900, alarm.time.tm_mon+1,
+ alarm.time.tm_mday,
+ alarm.pending ? " (pending)" : "");
+}
+
+
+static void set_alarm_abs(const char *t, const char *day)
+{
+ fprintf(stderr, "not yet implemented :-)\n");
+ exit(1);
+}
+
+
+static void set_alarm_delta(time_t delta)
+{
+ struct rtc_wkalrm alarm;
+ struct tm tm, *tmp;
+ time_t t;
+
+ read_time(&alarm.time);
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_sec = alarm.time.tm_sec;
+ tm.tm_min = alarm.time.tm_min;
+ tm.tm_hour = alarm.time.tm_hour;
+ tm.tm_mday = alarm.time.tm_mday;
+ tm.tm_mon = alarm.time.tm_mon;
+ tm.tm_year = alarm.time.tm_year;
+ t = mktime(&tm);
+ if (t == (time_t) -1) {
+ fprintf(stderr, "mktime: error\n");
+ exit(1);
+ }
+ t += delta;
+ tmp = localtime(&t);
+ if (!tmp) {
+ fprintf(stderr, "localtime_r: error\n");
+ exit(1);
+ }
+ alarm.time.tm_sec = tmp->tm_sec;
+ alarm.time.tm_min = tmp->tm_min;
+ alarm.time.tm_hour = tmp->tm_hour;
+ alarm.time.tm_mday = tmp->tm_mday;
+ alarm.time.tm_mon = tmp->tm_mon;
+ alarm.time.tm_year = tmp->tm_year;
+ alarm.enabled = 1;
+ write_alarm(&alarm);
+}
+
+
+static void set_alarm_rel(const char *delta)
+{
+ unsigned long n;
+ char *end;
+
+ n = strtoul(delta, &end, 10);
+ if (!strcmp(end, "d") || !strcmp(end, "day") || !strcmp(end, "days"))
+ n *= 24*3600;
+ else if (!strcmp(end, "h") || !strcmp(end, "hour") ||
+ !strcmp(end, "hours"))
+ n *= 3600;
+ else if (!strcmp(end, "m") || !strcmp(end, "min") ||
+ !strcmp(end, "mins"))
+ n *= 60;
+ else if (strcmp(end, "s") && strcmp(end, "sec") &&
+ strcmp(end, "secs")) {
+ fprintf(stderr, "invalid delta time \"%s\"\n", delta);
+ exit(1);
+ }
+ set_alarm_delta(n);
+}
+
+
+static void disable_alarm(void)
+{
+ struct rtc_wkalrm alarm;
+
+ read_alarm(&alarm);
+ alarm.enabled = 0;
+ write_alarm(&alarm);
+}
+
+
+static void set_alarm_24h(const char *t)
+{
+ fprintf(stderr, "not yet implemented :-)\n");
+ exit(1);
+}
+
+
+static void set_alarm(const char *when)
+{
+ if (*when == '+')
+ set_alarm_rel(when+1);
+ else
+ set_alarm_24h(when);
+}
+
+
+/* ----- Command line parsing ---------------------------------------------- */
+
+
+static void usage(const char *name)
+{
+ fprintf(stderr,
+"usage: %s [-d device]\n"
+" %s [-d device] hh:mm[:ss] [[yyyy-]mm-dd]\n"
+" %s [-d device] +Nunit\n\n"
+" unit is d[ay[s]], h[our[s]] m[in[s]], or s[ec[s]]\n\n"
+" -d device open the specified RTC device (default: %s)\n"
+ , name, name, name, DEFAULT_RTC);
+ exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "d:")) != EOF)
+ switch (c) {
+ case 'd':
+ device = optarg;
+ break;
+ default:
+ usage(*argv);
+ }
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ perror(device);
+ exit(1);
+ }
+
+ switch (argc-optind) {
+ case 0:
+ show_alarm();
+ break;
+ case 1:
+ if (!strcmp(argv[optind], "off"))
+ disable_alarm();
+ else
+ set_alarm(argv[optind]);
+ break;
+ case 2:
+ set_alarm_abs(argv[optind], argv[optind+1]);
+ break;
+ default:
+ usage(*argv);
+ }
+ return 0;
+}
More information about the commitlog
mailing list