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