diff --git a/mote/sgtools/GNUmakefile b/mote/sgtools/GNUmakefile new file mode 100644 index 0000000000000000000000000000000000000000..fc27debdae4ef1c6091a9d6a93569e4d54819a9e --- /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 0000000000000000000000000000000000000000..2a9d863ec297a3f4de962aa5dab3780d842a7a38 --- /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 0000000000000000000000000000000000000000..f235725702e37e4eaa3886bd6dad144b4f52c347 --- /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 0000000000000000000000000000000000000000..37e4cf14d8e12ba3b3f73c53965f459637f29119 --- /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 0000000000000000000000000000000000000000..5aa6ab9e607a7b4c3c76565053d01a5f525e80ad --- /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); + } +}