Commit cb7c1946 authored by Robert Ricci's avatar Robert Ricci

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.
parent 5f7792e3
#
# 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
/*
* $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];
}
/*
* $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 */
/*
* 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);
}
}
/*
* 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);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment