From cb7c194658266f22d467c333732b80387c5bde94 Mon Sep 17 00:00:00 2001
From: Robert Ricci <ricci@cs.utah.edu>
Date: Thu, 16 Dec 2004 17:53:32 +0000
Subject: [PATCH] Add sgtools, a couple tools to handle motes hosted on
 stargates.

Right now, these have to be built on ibapah, because it's got the
cross compiler neeeded.

Includes some of Kirk's SGGPIO code. This should probably get moved
to some other directory and made into more of a library.
---
 mote/sgtools/GNUmakefile |  31 ++++
 mote/sgtools/SGGPIO.C    | 154 +++++++++++++++++++
 mote/sgtools/SGGPIO.h    |  82 ++++++++++
 mote/sgtools/moteleds.C  | 318 +++++++++++++++++++++++++++++++++++++++
 mote/sgtools/motepower.C |  73 +++++++++
 5 files changed, 658 insertions(+)
 create mode 100644 mote/sgtools/GNUmakefile
 create mode 100644 mote/sgtools/SGGPIO.C
 create mode 100644 mote/sgtools/SGGPIO.h
 create mode 100644 mote/sgtools/moteleds.C
 create mode 100644 mote/sgtools/motepower.C

diff --git a/mote/sgtools/GNUmakefile b/mote/sgtools/GNUmakefile
new file mode 100644
index 0000000000..fc27debdae
--- /dev/null
+++ b/mote/sgtools/GNUmakefile
@@ -0,0 +1,31 @@
+#
+# EMULAB-COPYRIGHT
+# Copyright (c) 2004 University of Utah and the Flux Group.
+# All rights reserved.
+#
+
+#
+# These are the paths to the ARM cross-compiler on ibapah.flux.utah.edu -
+# should put something more general here
+#
+CXX=/usr/local/arm/3.4.1/bin/arm-linux-g++
+CXXFLAGS=-static
+STRIP=/usr/local/arm/3.4.1/bin/arm-linux-strip
+CC=/usr/local/arm/3.4.1/bin/arm-linux-gcc
+
+OBJS=SGGPIO.o
+
+all: motepower moteleds
+
+motepower: motepower.C $(OBJS)
+	$(CXX) $(CXXFLAGS) -o motepower motepower.C $(OBJS)
+	$(STRIP) motepower
+
+moteleds: moteleds.C $(OBJS)
+	$(CXX) $(CXXFLAGS) -o moteleds moteleds.C $(OBJS)
+	$(STRIP) moteleds
+
+
+
+clean:
+	rm -f $(OBJS) motepower moteleds
diff --git a/mote/sgtools/SGGPIO.C b/mote/sgtools/SGGPIO.C
new file mode 100644
index 0000000000..2a9d863ec2
--- /dev/null
+++ b/mote/sgtools/SGGPIO.C
@@ -0,0 +1,154 @@
+/*
+ * $Id: SGGPIO.C,v 1.1 2004-12-16 17:53:32 ricci Exp $
+ *
+ ****************************************************************************
+ *
+ * uisp - The Micro In-System Programmer for Atmel AVR microcontrollers.
+ * Copyright (C) 2003 University of Utah and The Flux Group
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ ****************************************************************************
+ */
+
+/*
+  SGGPIO.C
+  
+  Direct Stargate/PXA GPIO Access
+  
+*/
+
+
+#include "SGGPIO.h"
+
+char *pxa_reg_names[] = {"GPLR", "GPDR", "GPSR", "GPCR"};
+
+int 
+SGGPIO_PORT::setDir(int pin, unsigned int indir) {
+  
+  unsigned int val = readGPIO(PXA_GPDR, GPIO_nr(pin));
+  
+  if (indir) {
+    val = val | GPIO_bit(pin);
+  } else {
+    val = val & ~(GPIO_bit(pin));
+  }
+  
+  writeGPIO(PXA_GPDR, GPIO_nr(pin), val);
+  
+  return 0;
+}
+
+int 
+SGGPIO_PORT::setPin(int pin, unsigned int inval) {
+  if (inval) {
+    writeGPIO(PXA_GPSR, GPIO_nr(pin), GPIO_bit(pin));
+  } else {
+    writeGPIO(PXA_GPCR, GPIO_nr(pin), GPIO_bit(pin));
+  }
+  return 0;
+}
+
+int 
+SGGPIO_PORT::readPin(int pin) {
+  return ((readGPIO(PXA_GPLR, GPIO_nr(pin)) & GPIO_bit(pin)) >> (0x1f & pin));
+}
+
+unsigned int 
+SGGPIO_PORT::readGPIO(PXA_REG reg,  int regnum) {
+  int fdesc = getGPIO(reg, regnum);
+  char buf[16];
+  int cnt = 0;
+  unsigned int retval = 0;
+
+  
+  if (! fdesc) {
+    printf("Couldn't get GPIO handle\n");
+    return 0;
+  }
+
+  if ((cnt = pread(fdesc, buf, sizeof(buf)-1, 0)) <= 0) {
+    printf("Error reading GPIO register\n");
+    return 0;
+  }
+
+  buf[cnt] = '\0';
+  retval = strtoul(buf, NULL, 0);
+  return retval;
+}
+
+int 
+SGGPIO_PORT::writeGPIO(PXA_REG reg, int regnum, unsigned int value) {
+  int fdesc = getGPIO(reg, regnum);
+  char buf[16];
+  int len;
+  
+  if (! fdesc) {
+    printf("Couldn't get GPIO handle\n");
+    return -1;
+  }
+  
+  len = sprintf(buf, "0x%08X\n", value);
+  
+  if (pwrite(fdesc, buf, len, 0) < 0) {
+    perror("Problem setting GPIO register");
+    printf("Register: %s%d\n", PXA_REG_NAME(reg), regnum);
+    printf("fdesc: %d\n", fdesc);
+    printf("Data: %s\n", buf);
+    return -1;
+  }
+
+  return 0;
+}
+
+SGGPIO_PORT::SGGPIO_PORT() {
+  int i, j;
+  
+  for (i = 0; i < NUM_REGS; ++i) {
+    for (j = 0; j < NUM_REGNUMS; ++j) {
+      GPIO_fds[i][j] = 0;
+    }
+  }
+}
+
+SGGPIO_PORT::~SGGPIO_PORT() {
+  int i, j;
+
+  for (i = 0; i < NUM_REGS; ++i) {
+    for (j = 0; j < NUM_REGNUMS; ++j) {
+      if (GPIO_fds[i][j]) {
+        close(GPIO_fds[i][j]);
+        GPIO_fds[i][j] = 0;
+      }
+    }
+  }
+}
+
+
+int 
+SGGPIO_PORT::getGPIO(PXA_REG reg, int regnum) {
+  char gpioPath[256];
+  
+  if (! GPIO_fds[reg][regnum]) {
+    sprintf(gpioPath, "%s/%s%d", PROC_REG_PREFIX, PXA_REG_NAME(reg), regnum);
+    if ((GPIO_fds[reg][regnum] = open(gpioPath, O_RDWR | O_FSYNC, 0)) < 0) {
+      printf("Error opening %s proc file: %s\n", PXA_REG_NAME(reg), 
+             strerror(errno));
+      return -1;
+    }
+  }
+  
+  return GPIO_fds[reg][regnum];
+}
diff --git a/mote/sgtools/SGGPIO.h b/mote/sgtools/SGGPIO.h
new file mode 100644
index 0000000000..f235725702
--- /dev/null
+++ b/mote/sgtools/SGGPIO.h
@@ -0,0 +1,82 @@
+/*
+ * $Id: SGGPIO.h,v 1.1 2004-12-16 17:53:32 ricci Exp $
+ *
+ ****************************************************************************
+ *
+ * uisp - The Micro In-System Programmer for Atmel AVR microcontrollers.
+ * Copyright (C) 2003 University of Utah and The Flux Group
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ ****************************************************************************
+ */
+
+/*
+  SGGPIO.h
+  
+  Direct Stargate/PXA GPIO Access
+  
+*/
+
+#ifndef __SGGPIO_H
+#define __SGGPIO_H
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+#define GPIO_bit(x)	(1 << ((x) & 0x1f))
+#define GPIO_nr(x)      ((x) >> 5)
+
+enum PXA_REG {
+  PXA_GPLR = 0,
+  PXA_GPDR = 1,
+  PXA_GPSR = 2,
+  PXA_GPCR = 3
+};
+#define NUM_REGS 4
+#define NUM_REGNUMS 3
+
+extern char *pxa_reg_names[];
+
+#define PXA_REG_NAME(reg) pxa_reg_names[(reg)]
+
+#define PROC_REG_PREFIX "/proc/cpu/registers"
+
+class SGGPIO_PORT {
+
+public:
+
+  int setDir(int pin, unsigned int indir);
+  int setPin(int pin, unsigned int inval);
+  int readPin(int pin);
+  unsigned int readGPIO(PXA_REG reg,  int regnum);
+  int writeGPIO(PXA_REG reg, int regnum, unsigned int value);
+  SGGPIO_PORT();
+  ~SGGPIO_PORT();
+
+private:
+
+  int getGPIO(PXA_REG reg, int regnum);
+  int GPIO_fds[NUM_REGS][NUM_REGNUMS];
+};
+
+#endif /* __SGGPIO_H */
diff --git a/mote/sgtools/moteleds.C b/mote/sgtools/moteleds.C
new file mode 100644
index 0000000000..37e4cf14d8
--- /dev/null
+++ b/mote/sgtools/moteleds.C
@@ -0,0 +1,318 @@
+/*
+ * EMULAB-COPYRIGHT
+ * Copyright (c) 2004 University of Utah and the Flux Group.
+ * All rights reserved.
+ */
+
+/*
+ * moteleds.C - program to read the mote LED pins on a Stargate, and display
+ * them: on the stargate's LEDs, on the command line, or out a TCP socket
+ */
+
+
+/*
+ * These seem to make things happier when compiling on Linux
+ */
+#ifdef __linux__
+#define __PREFER_BSD
+#define __USE_BSD
+#define __FAVOR_BSD
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <arpa/inet.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#ifdef __linux__
+#include <linux/sockios.h>
+#else
+#include <sys/sockio.h>
+#endif
+
+#include "SGGPIO.h"
+
+/*
+ * Mote LEDs
+ */
+#define MOTELED_RED_PIN    24
+#define MOTELED_GREEN_PIN  28
+#define MOTELED_YELLOW_PIN 29
+
+/*
+ * Stargate LEDs
+ */
+#define SGLED_YELLOW_PIN 62
+#define SGLED_GREEN_PIN  63
+#define SGLED_RED_PIN    64
+
+/*
+ * LED IOCTL constants - derived from linux/led.h
+ */
+#define LED_DEV "/dev/platx/led" 
+#define CONSUS_LED_IOCTL_MAGIG 'g'
+#define CLED_IOSET          _IO (CONSUS_LED_IOCTL_MAGIG, 1)
+#define CLED_IOGET          _IOR(CONSUS_LED_IOCTL_MAGIG, 2, int*)
+#define CLED_IOSTARTAUTO    _IO (CONSUS_LED_IOCTL_MAGIG, 3)
+#define CLED_IOSTOPAUTO     _IO (CONSUS_LED_IOCTL_MAGIG, 4)
+#define CLED_IOAUTOSTATUS   _IOR(CONSUS_LED_IOCTL_MAGIG, 5, int*)
+#define CLED_RADIO_RESET    _IO (CONSUS_LED_IOCTL_MAGIG, 6)
+
+#define LED_GREEN      (1 << 13)
+#define LED_RED        (1 << 15)
+#define LED_YELLOW     (1 << 14)
+#define LED_MASK       (LED_RED|LED_GREEN|LED_YELLOW)
+
+// Port to listen on
+#define PORT 1812
+
+// How many clients we can handle at once
+#define MAX_CLIENTS 64
+
+// Which mode we're in
+enum modes {
+    MODE_NONE   = 0x0,
+    MODE_MIRROR = 0x1,
+    MODE_PRINT  = 0x2,
+    MODE_EVENT  = 0x4,
+    MODE_SOCKET = 0x8
+};
+
+void usage() {
+	fprintf(stderr,"Usage: moteleds <-m | -p | -e | -s> [-t sleeptime]\n");
+	fprintf(stderr,"  -m  Mirror mode - set stargate LEDs\n");
+	fprintf(stderr,"  -p  Print mode - print LED status to stdout\n");
+	//fprintf(stderr,"  -e  Event mode - set events on LED state change\n");
+	fprintf(stderr,"  -s  Socket mode - open up a socket\n");
+	fprintf(stderr,"  -d  daemonize\n");
+	fprintf(stderr,"  -t  Sleep time in microseconds\n");
+	exit(1);
+}
+
+int main(int argc, char **argv) {
+
+    unsigned int mode = MODE_NONE;
+    int naptime = 0;
+
+    // Process command-line args
+    int ch;
+    bool daemonize = false;
+    while ((ch = getopt(argc, argv, "mpesdt:")) != -1)
+	switch (ch) {
+	    case 'm':
+		mode |= MODE_MIRROR;
+		break;
+	    case 'p':
+		mode |= MODE_PRINT;
+		break;
+	    case 'e':
+		mode |= MODE_EVENT;
+		break;
+	    case 's':
+		mode |= MODE_SOCKET;
+		break;
+	    case 'd':
+		daemonize = true;
+		break;
+	    case 't':
+		if (!sscanf(optarg,"%i",&naptime)) {
+		    usage();
+		}
+		break;
+	    case '?':
+	    default:
+		usage();
+	}
+    argc -= optind;
+    argv += optind;
+
+    if (argc) {
+	usage();
+    }
+
+    if (mode == MODE_NONE) {
+	usage();
+    }
+
+
+    // Set the GPIO pins to read from the mote LEDs
+    SGGPIO_PORT sggpio;
+    sggpio.setDir(MOTELED_YELLOW_PIN,0);
+    sggpio.setDir(MOTELED_GREEN_PIN,0);
+    sggpio.setDir(MOTELED_RED_PIN,0);
+
+    if (!naptime) {
+	naptime = 10 * 1000; // 100Hz
+    }
+
+    // We're going to mirror the mote LEDs to the stargate LEDs, so open up
+    // a file to control the SG LEDs
+    int ledfd = -1;
+    if (mode & MODE_MIRROR) {
+	ledfd = open(LED_DEV, O_RDWR);
+	if (ledfd < 0) {
+	    fprintf(stderr, "Open error: %s\n", LED_DEV);
+	    return 1;
+	}
+	// Turn off the automatic LED pattern
+	if (ioctl (ledfd, CLED_IOSTOPAUTO) < 0) {
+	    fprintf (stderr, "ioctl stop auto error: %s\n", LED_DEV);
+	    return 1;
+	}
+    }
+
+    // If we're supposed to write LED state change events to a socket, open
+    // that up now
+    int sockfd = -1;
+    if (mode & MODE_SOCKET) {
+	struct protoent *proto = getprotobyname("TCP");
+	sockfd = socket(AF_INET,SOCK_STREAM,proto->p_proto);
+	if (sockfd < 0) {     
+	    perror("Creating socket");
+	    exit(1);
+	}                               
+
+	// Set SO_RESEADDUR to make it easier to kill and restart this daemon
+        int opt = 1;
+        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) < 0)
+                perror("SO_REUSEADDR");
+	
+	// Make the socket non-blocking
+        if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0)
+                perror("O_NONBLOCK");
+
+	struct sockaddr_in address;
+        address.sin_family = AF_INET;
+        address.sin_port = htons(PORT);
+        address.sin_addr.s_addr = INADDR_ANY;
+
+        if (bind(sockfd,(struct sockaddr*)(&address),sizeof(address))) {
+                perror("Binding socket");
+                exit(1);
+        }
+
+        if (listen(sockfd,-1)) {
+                perror("Listening on socket");
+                exit(1);
+        }
+
+        /*
+         * Ignore SIGPIPE - we'll detect the remote end closing the connection
+         * by a failed write() .
+         */
+	struct sigaction action;
+        action.sa_handler = SIG_IGN;
+        sigaction(SIGPIPE,&action,NULL);
+
+    }
+
+    // Daemonize if we're supposed to
+    if (daemonize) {
+	daemon(0,0);
+    }
+
+    /*
+     * Main loop
+     */
+    unsigned int current_status, old_status;
+    // Bogus value so that we will detect a change the first time through
+    old_status = 31337;
+
+    // FD of the clients for our socket
+    int clientfds[MAX_CLIENTS];
+    for (int i = 0; i < MAX_CLIENTS; i++) { clientfds[i] = -1; }
+    bool newclient = false;
+    int current_clients = 0;
+    while(1) {
+	// If we have a socket, try to accept connections
+	if ((mode & MODE_SOCKET) && sockfd) {
+
+	    struct sockaddr client_addr;
+	    size_t client_addrlen;
+
+	    int newclientfd = accept(sockfd,&client_addr,&client_addrlen);
+	    if (newclientfd >= 0) {
+		if (current_clients == MAX_CLIENTS) {
+		    // Bummer, too many
+		    close(newclientfd);
+		}
+		newclient = true;
+		for (int i = 0; i < MAX_CLIENTS; i++) {
+		    if (clientfds[i] == -1) {
+			clientfds[i] = newclientfd;
+			current_clients++;
+			break;
+		    }
+		}
+	    }
+	}
+
+	// Read mote pin connectors
+	int yellow = sggpio.readPin(MOTELED_YELLOW_PIN);
+	int green = sggpio.readPin(MOTELED_GREEN_PIN);
+	int red = sggpio.readPin(MOTELED_RED_PIN);
+
+	// Mote LEDs use negative logic, reverse them
+	if (yellow) { yellow = 0; } else { yellow = 1; }
+	if (green) { green = 0; } else { green = 1; }
+	if (red) { red = 0; } else { red = 1; }
+
+	// In mirroring mode, set up a patter for the SG LEDs and ioctl() it
+	// into place
+	if (mode & MODE_MIRROR) {
+	    int ledpattern = 0;
+	    if (yellow) { ledpattern |= LED_RED; }
+	    if (green) { ledpattern |= LED_GREEN; }
+	    if (red) { ledpattern |= LED_YELLOW; }
+	    if (ioctl (ledfd, CLED_IOSET, ledpattern) < 0) {
+		fprintf (stderr, "ioctl set error: %s\n", LED_DEV);
+		exit(1);
+	    } 
+	}
+
+	// Check to see if what we got this time was different from last time
+	current_status = (red << 2) | (green << 1) | yellow;
+	if (old_status != current_status) {
+	    // In printing mode, do just that
+	    if (mode & MODE_PRINT) {
+		printf("%i %i %i\n",red,green,yellow);
+	    }
+	}
+
+	if ((old_status != current_status) || newclient) {
+	    // If we have a socket, print on that
+	    if ((mode & MODE_SOCKET) && (current_clients > 0)) {
+		char outbuf[1024];
+		snprintf(outbuf,1024,"%i %i %i\n",red,green,yellow);
+		for (int i = 0; i <= MAX_CLIENTS; i++) {
+		    int clientfd = clientfds[i];
+		    if (clientfd == -1) {
+			continue;
+		    }
+		    if (write(clientfd,outbuf,strlen(outbuf)) < 0) {
+			// Detect disconnected clients
+			if (errno != EPIPE) {
+			    perror("write");
+			}
+			close(clientfd);
+			clientfds[i] = -1;
+			current_clients--;
+		    }
+		}
+	    }
+	    newclient = false;
+	}
+	old_status = current_status;
+
+	// Get some, go again
+	usleep(naptime);
+    }
+}
diff --git a/mote/sgtools/motepower.C b/mote/sgtools/motepower.C
new file mode 100644
index 0000000000..5aa6ab9e60
--- /dev/null
+++ b/mote/sgtools/motepower.C
@@ -0,0 +1,73 @@
+
+/*
+ * EMULAB-COPYRIGHT
+ * Copyright (c) 2004 University of Utah and the Flux Group.
+ * All rights reserved.
+ */
+
+/*
+ * motepower.C - turn the power to a mote on a stargate "on" or "off" by
+ * toggling its RSTN pin
+ */
+
+#include "SGGPIO.h"
+
+// Pin used to reset the ATMega microcontroller
+#define RSTN_PIN 77
+
+// The RSTN pin is negative logic
+#define MOTE_ON 1
+#define MOTE_OFF 0
+
+void usage() {
+	fprintf(stderr,"Usage: motepower <on | off | cycle>\n");
+	exit(1);
+}
+
+int main(int argc, char **argv) {
+    /*
+     * Handle command-line argument
+     */
+    if (argc != 2) {
+	usage();
+    }
+
+    bool turnoff = false;
+    bool turnon = false;
+    if (!strcmp(argv[1],"on")) {
+	turnon = true;
+    } else if (!strcmp(argv[1],"off")) {
+	turnoff = true;
+    } else if (!strcmp(argv[1],"cycle")) {
+	turnon = turnoff = true;
+    } else {
+	usage();
+    }
+
+    /*
+     * Set the pin for output
+     */
+    SGGPIO_PORT sggpio;
+    sggpio.setDir(RSTN_PIN,1);
+
+    /*
+     * Turn off the mote, if we're supposed to
+     */
+    if (turnoff) {
+	sggpio.setPin(RSTN_PIN,MOTE_OFF);
+    }
+    
+    /*
+     * If cycling, give it a moment
+     */
+    if (turnon && turnoff) {
+	usleep(500 * 1000); // .5 seconds
+    }
+
+    /*
+     * Turn on the mote, if we're supposed to
+     */
+    if (turnon) {
+	sggpio.setPin(RSTN_PIN,MOTE_ON);
+    }
+}
-- 
GitLab