private JButton button;
public ColorCellEditor(String title) {
- button = new JButton();
- final JColorChooser chooser = new JColorChooser();
- final JDialog dialog = JColorChooser.createDialog
- (button, title, true, chooser,
- new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- color = chooser.getColor();
- } },
- null);
+ button = new JButton();
+ final JColorChooser chooser = new JColorChooser();
+ final JDialog dialog = JColorChooser.createDialog
+ (button, title, true, chooser,
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ color = chooser.getColor();
+ } },
+ null);
- button.setBorderPainted(false);
- button.addActionListener
- (new ActionListener () {
- public void actionPerformed(ActionEvent e) {
- button.setBackground(color);
- chooser.setColor(color);
- dialog.setVisible(true);
- fireEditingStopped();
- } } );
-
+ button.setBorderPainted(false);
+ button.addActionListener
+ (new ActionListener () {
+ public void actionPerformed(ActionEvent e) {
+ button.setBackground(color);
+ chooser.setColor(color);
+ dialog.setVisible(true);
+ fireEditingStopped();
+ } } );
+
}
public Object getCellEditorValue() { return color; }
private Oscilloscope parent;
Data(Oscilloscope parent) {
- this.parent = parent;
+ this.parent = parent;
}
/* Data received from mote nodeId containing NREADINGS samples from
messageId * NREADINGS onwards. Tell parent if this is a new node. */
void update(int nodeId, int messageId, int readings[]) {
- if (nodeId >= nodes.length) {
- int newLength = nodes.length * 2;
- if (nodeId >= newLength)
- newLength = nodeId + 1;
+ if (nodeId >= nodes.length) {
+ int newLength = nodes.length * 2;
+ if (nodeId >= newLength)
+ newLength = nodeId + 1;
- Node newNodes[] = new Node[newLength];
- System.arraycopy(nodes, 0, newNodes, 0, nodes.length);
- nodes = newNodes;
- }
- Node node = nodes[nodeId];
- if (node == null) {
- nodes[nodeId] = node = new Node(nodeId);
- parent.newNode(nodeId);
- }
- node.update(messageId, readings);
+ Node newNodes[] = new Node[newLength];
+ System.arraycopy(nodes, 0, newNodes, 0, nodes.length);
+ nodes = newNodes;
+ }
+ Node node = nodes[nodeId];
+ if (node == null) {
+ nodes[nodeId] = node = new Node(nodeId);
+ parent.newNode(nodeId);
+ }
+ node.update(messageId, readings);
}
/* Return value of sample x for mote nodeId, or -1 for missing data */
int getData(int nodeId, int x) {
- if (nodeId >= nodes.length || nodes[nodeId] == null)
- return -1;
- return nodes[nodeId].getData(x);
+ if (nodeId >= nodes.length || nodes[nodeId] == null)
+ return -1;
+ return nodes[nodeId].getData(x);
}
/* Return number of last known sample on mote nodeId. Returns 0 for
unknown motes. */
int maxX(int nodeId) {
- if (nodeId >= nodes.length || nodes[nodeId] == null)
- return 0;
- return nodes[nodeId].maxX();
+ if (nodeId >= nodes.length || nodes[nodeId] == null)
+ return 0;
+ return nodes[nodeId].maxX();
}
/* Return number of largest known sample on all motes (0 if there are no
motes) */
int maxX() {
- int max = 0;
+ int max = 0;
- for (int i = 0; i < nodes.length; i++)
- if (nodes[i] != null) {
- int nmax = nodes[i].maxX();
+ for (int i = 0; i < nodes.length; i++)
+ if (nodes[i] != null) {
+ int nmax = nodes[i].maxX();
- if (nmax > max)
- max = nmax;
- }
+ if (nmax > max)
+ max = nmax;
+ }
- return max;
+ return max;
}
}
double xscale, yscale;
void updateConversion() {
- height = getHeight() - BORDER_TOP - BORDER_BOTTOM;
- width = getWidth() - BORDER_LEFT - BORDER_RIGHT;
- if (height < 1)
- height = 1;
- if (width < 1)
- width = 1;
- xscale = (double)width / (gx1 - gx0 + 1);
- yscale = (double)height / (gy1 - gy0 + 1);
+ height = getHeight() - BORDER_TOP - BORDER_BOTTOM;
+ width = getWidth() - BORDER_LEFT - BORDER_RIGHT;
+ if (height < 1)
+ height = 1;
+ if (width < 1)
+ width = 1;
+ xscale = (double)width / (gx1 - gx0 + 1);
+ yscale = (double)height / (gy1 - gy0 + 1);
}
Graphics makeClip(Graphics g) {
- return g.create(BORDER_LEFT, BORDER_TOP, width, height);
+ return g.create(BORDER_LEFT, BORDER_TOP, width, height);
}
// Note that these do not include the border offset!
int screenX(int gx) {
- return (int)(xscale * (gx - gx0) + 0.5);
+ return (int)(xscale * (gx - gx0) + 0.5);
}
int screenY(int gy) {
- return (int)(height - yscale * (gy - gy0));
+ return (int)(height - yscale * (gy - gy0));
}
int graphX(int sx) {
- return (int)(sx / xscale + gx0 + 0.5);
+ return (int)(sx / xscale + gx0 + 0.5);
}
Graph(Window parent) {
- this.parent = parent;
- gy0 = 0; gy1 = 0xffff;
- gx0 = 0; gx1 = MIN_WIDTH << scale;
+ this.parent = parent;
+ gy0 = 0; gy1 = 0xffff;
+ gx0 = 0; gx1 = MIN_WIDTH << scale;
}
void rightDrawString(Graphics2D g, String s, int x, int y) {
- TextLayout layout =
- new TextLayout(s, parent.smallFont, g.getFontRenderContext());
- Rectangle2D bounds = layout.getBounds();
- layout.draw(g, x - (float)bounds.getWidth(), y + (float)bounds.getHeight() / 2);
+ TextLayout layout =
+ new TextLayout(s, parent.smallFont, g.getFontRenderContext());
+ Rectangle2D bounds = layout.getBounds();
+ layout.draw(g, x - (float)bounds.getWidth(), y + (float)bounds.getHeight() / 2);
}
protected void paintComponent(Graphics g) {
- Graphics2D g2d = (Graphics2D)g;
+ Graphics2D g2d = (Graphics2D)g;
- /* Repaint. Synchronize on Oscilloscope to avoid data changing.
- Simply clear panel, draw Y axis and all the mote graphs. */
- synchronized (parent.parent) {
- updateConversion();
- g2d.setColor(Color.BLACK);
- g2d.fillRect(0, 0, getWidth(), getHeight());
- drawYAxis(g2d);
+ /* Repaint. Synchronize on Oscilloscope to avoid data changing.
+ Simply clear panel, draw Y axis and all the mote graphs. */
+ synchronized (parent.parent) {
+ updateConversion();
+ g2d.setColor(Color.BLACK);
+ g2d.fillRect(0, 0, getWidth(), getHeight());
+ drawYAxis(g2d);
- Graphics clipped = makeClip(g2d);
- int count = parent.moteListModel.size();
- for (int i = 0; i < count; i++) {
- clipped.setColor(parent.moteListModel.getColor(i));
- drawGraph(clipped, parent.moteListModel.get(i));
- }
- }
+ Graphics clipped = makeClip(g2d);
+ int count = parent.moteListModel.size();
+ for (int i = 0; i < count; i++) {
+ clipped.setColor(parent.moteListModel.getColor(i));
+ drawGraph(clipped, parent.moteListModel.get(i));
+ }
+ }
}
/* Draw the Y-axis */
protected void drawYAxis(Graphics2D g) {
- int axis_x = BORDER_LEFT - 1;
- int height = getHeight() - BORDER_BOTTOM - BORDER_TOP;
-
- g.setColor(Color.WHITE);
- g.drawLine(axis_x, BORDER_TOP, axis_x, BORDER_TOP + height - 1);
-
- /* Draw a reasonable set of tick marks */
- int nTicks = height / TICK_SPACING;
- if (nTicks > MAX_TICKS)
- nTicks = MAX_TICKS;
-
- int tickInterval = (gy1 - gy0 + 1) / nTicks;
- if (tickInterval == 0)
- tickInterval = 1;
-
- /* Tick interval should be of the family A * 10^B,
- where A = 1, 2 * or 5. We tend more to rounding A up, to reduce
- rather than increase the number of ticks. */
- int B = (int)(Math.log(tickInterval) / Math.log(10));
- int A = (int)(tickInterval / Math.pow(10, B) + 0.5);
- if (A > 2) A = 5;
- else if (A > 5) A = 10;
-
- tickInterval = A * (int)Math.pow(10, B);
-
- /* Ticks are printed at multiples of tickInterval */
- int tick = ((gy0 + tickInterval - 1) / tickInterval) * tickInterval;
- while (tick <= gy1) {
- int stick = screenY(tick) + BORDER_TOP;
- rightDrawString(g, "" + tick, axis_x - TICK_WIDTH / 2 - 2, stick);
- g.drawLine(axis_x - TICK_WIDTH / 2, stick,
- axis_x - TICK_WIDTH / 2 + TICK_WIDTH, stick);
- tick += tickInterval;
- }
-
+ int axis_x = BORDER_LEFT - 1;
+ int height = getHeight() - BORDER_BOTTOM - BORDER_TOP;
+
+ g.setColor(Color.WHITE);
+ g.drawLine(axis_x, BORDER_TOP, axis_x, BORDER_TOP + height - 1);
+
+ /* Draw a reasonable set of tick marks */
+ int nTicks = height / TICK_SPACING;
+ if (nTicks > MAX_TICKS)
+ nTicks = MAX_TICKS;
+
+ int tickInterval = (gy1 - gy0 + 1) / nTicks;
+ if (tickInterval == 0)
+ tickInterval = 1;
+
+ /* Tick interval should be of the family A * 10^B,
+ where A = 1, 2 * or 5. We tend more to rounding A up, to reduce
+ rather than increase the number of ticks. */
+ int B = (int)(Math.log(tickInterval) / Math.log(10));
+ int A = (int)(tickInterval / Math.pow(10, B) + 0.5);
+ if (A > 2) A = 5;
+ else if (A > 5) A = 10;
+
+ tickInterval = A * (int)Math.pow(10, B);
+
+ /* Ticks are printed at multiples of tickInterval */
+ int tick = ((gy0 + tickInterval - 1) / tickInterval) * tickInterval;
+ while (tick <= gy1) {
+ int stick = screenY(tick) + BORDER_TOP;
+ rightDrawString(g, "" + tick, axis_x - TICK_WIDTH / 2 - 2, stick);
+ g.drawLine(axis_x - TICK_WIDTH / 2, stick,
+ axis_x - TICK_WIDTH / 2 + TICK_WIDTH, stick);
+ tick += tickInterval;
+ }
+
}
/* Draw graph for mote nodeId */
protected void drawGraph(Graphics g, int nodeId) {
- SingleGraph sg = new SingleGraph(g, nodeId);
+ SingleGraph sg = new SingleGraph(g, nodeId);
- if (gx1 - gx0 >= width) // More points than pixels-iterate by pixel
- for (int sx = 0; sx < width; sx++)
- sg.nextPoint(g, graphX(sx), sx);
- else // Less points than pixel-iterate by points
- for (int gx = gx0; gx <= gx1; gx++)
- sg.nextPoint(g, gx, screenX(gx));
+ if (gx1 - gx0 >= width) // More points than pixels-iterate by pixel
+ for (int sx = 0; sx < width; sx++)
+ sg.nextPoint(g, graphX(sx), sx);
+ else // Less points than pixel-iterate by points
+ for (int gx = gx0; gx <= gx1; gx++)
+ sg.nextPoint(g, gx, screenX(gx));
}
/* Inner class to simplify drawing a graph. Simplify initialise it, then
feed it the X screen and graph coordinates, from left to right. */
private class SingleGraph {
- int lastsx, lastsy, nodeId;
+ int lastsx, lastsy, nodeId;
- /* Start drawing the graph mote id */
- SingleGraph(Graphics g, int id) {
- nodeId = id;
- lastsx = -1;
- lastsy = -1;
- }
+ /* Start drawing the graph mote id */
+ SingleGraph(Graphics g, int id) {
+ nodeId = id;
+ lastsx = -1;
+ lastsy = -1;
+ }
- /* Next point in mote's graph is at x value gx, screen coordinate sx */
- void nextPoint(Graphics g, int gx, int sx) {
- int gy = parent.parent.data.getData(nodeId, gx);
- int sy = -1;
+ /* Next point in mote's graph is at x value gx, screen coordinate sx */
+ void nextPoint(Graphics g, int gx, int sx) {
+ int gy = parent.parent.data.getData(nodeId, gx);
+ int sy = -1;
- if (gy >= 0) { // Ignore missing values
- double rsy = height - yscale * (gy - gy0);
+ if (gy >= 0) { // Ignore missing values
+ double rsy = height - yscale * (gy - gy0);
- // Ignore problem values
- if (rsy >= -1e6 && rsy <= 1e6)
- sy = (int)(rsy + 0.5);
+ // Ignore problem values
+ if (rsy >= -1e6 && rsy <= 1e6)
+ sy = (int)(rsy + 0.5);
- if (lastsy >= 0 && sy >= 0)
- g.drawLine(lastsx, lastsy, sx, sy);
- }
- lastsx = sx;
- lastsy = sy;
- }
+ if (lastsy >= 0 && sy >= 0)
+ g.drawLine(lastsx, lastsy, sx, sy);
+ }
+ lastsx = sx;
+ lastsy = sy;
+ }
}
/* Update X-axis range in GUI */
void updateXLabel() {
- parent.xLabel.setText("X: " + gx0 + " - " + gx1);
+ parent.xLabel.setText("X: " + gx0 + " - " + gx1);
}
/* Ensure that graph is nicely positioned on screen. max is the largest
sample number received from any mote. */
private void recenter(int max) {
- // New data will show up at the 3/4 point
- // The 2nd term ensures that gx1 will be >= max
- int scrollby = ((gx1 - gx0) >> 2) + (max - gx1);
- gx0 += scrollby;
- gx1 += scrollby;
- if (gx0 < 0) { // don't bother showing negative sample numbers
- gx1 -= gx0;
- gx0 = 0;
- }
- updateXLabel();
+ // New data will show up at the 3/4 point
+ // The 2nd term ensures that gx1 will be >= max
+ int scrollby = ((gx1 - gx0) >> 2) + (max - gx1);
+ gx0 += scrollby;
+ gx1 += scrollby;
+ if (gx0 < 0) { // don't bother showing negative sample numbers
+ gx1 -= gx0;
+ gx0 = 0;
+ }
+ updateXLabel();
}
/* New data received. Redraw graph, scrolling if necessary */
void newData() {
- int max = parent.parent.data.maxX();
+ int max = parent.parent.data.maxX();
- if (max > gx1 || max < gx0) // time to scroll
- recenter(max);
- repaint();
+ if (max > gx1 || max < gx0) // time to scroll
+ recenter(max);
+ repaint();
}
/* User set the X-axis scale to newScale */
void setScale(int newScale) {
- gx1 = gx0 + (MIN_WIDTH << newScale);
- scale = newScale;
- recenter(parent.parent.data.maxX());
- repaint();
+ gx1 = gx0 + (MIN_WIDTH << newScale);
+ scale = newScale;
+ recenter(parent.parent.data.maxX());
+ repaint();
}
/* User attempted to set Y-axis range to newy0..newy1. Refuse bogus
values (return false), or accept, redraw and return true. */
boolean setYAxis(int newy0, int newy1) {
- if (newy0 >= newy1 || newy0 < 0 || newy0 > 65535 ||
- newy1 < 0 || newy1 > 65535)
- return false;
- gy0 = newy0;
- gy1 = newy1;
- repaint();
- return true;
+ if (newy0 >= newy1 || newy0 < 0 || newy0 > 65535 ||
+ newy1 < 0 || newy1 > 65535)
+ return false;
+ gy0 = newy0;
+ gy1 = newy1;
+ repaint();
+ return true;
}
}
int dataStart, dataEnd;
Node(int _id) {
- id = _id;
+ id = _id;
}
/* Update data to hold received samples newDataIndex .. newEnd.
If we receive data with a lower index, we discard newer data
(we assume the mote rebooted). */
private void setEnd(int newDataIndex, int newEnd) {
- if (newDataIndex < dataStart || data == null) {
- /* New data is before the start of what we have. Just throw it
- all away and start again */
- dataStart = newDataIndex;
- data = new int[INCREMENT];
- }
- if (newEnd > dataStart + data.length) {
- /* Try extending first */
- if (data.length < MAX_SIZE) {
- int newLength = (newEnd - dataStart + INCREMENT - 1) / INCREMENT * INCREMENT;
- if (newLength >= MAX_SIZE)
- newLength = MAX_SIZE;
+ if (newDataIndex < dataStart || data == null) {
+ /* New data is before the start of what we have. Just throw it
+ all away and start again */
+ dataStart = newDataIndex;
+ data = new int[INCREMENT];
+ }
+ if (newEnd > dataStart + data.length) {
+ /* Try extending first */
+ if (data.length < MAX_SIZE) {
+ int newLength = (newEnd - dataStart + INCREMENT - 1) / INCREMENT * INCREMENT;
+ if (newLength >= MAX_SIZE)
+ newLength = MAX_SIZE;
- int[] newData = new int[newLength];
- System.arraycopy(data, 0, newData, 0, data.length);
- data = newData;
+ int[] newData = new int[newLength];
+ System.arraycopy(data, 0, newData, 0, data.length);
+ data = newData;
- }
- if (newEnd > dataStart + data.length) {
- /* Still doesn't fit. Squish.
- We assume INCREMENT >= (newEnd - newDataIndex), and ensure
- that dataStart + data.length - INCREMENT = newDataIndex */
- int newStart = newDataIndex + INCREMENT - data.length;
+ }
+ if (newEnd > dataStart + data.length) {
+ /* Still doesn't fit. Squish.
+ We assume INCREMENT >= (newEnd - newDataIndex), and ensure
+ that dataStart + data.length - INCREMENT = newDataIndex */
+ int newStart = newDataIndex + INCREMENT - data.length;
- if (dataStart + data.length > newStart)
- System.arraycopy(data, newStart - dataStart, data, 0,
- data.length - (newStart - dataStart));
- dataStart = newStart;
- }
- }
- /* Mark any missing data as invalid */
- for (int i = dataEnd < dataStart ? dataStart : dataEnd;
- i < newDataIndex; i++)
- data[i - dataStart] = -1;
+ if (dataStart + data.length > newStart)
+ System.arraycopy(data, newStart - dataStart, data, 0,
+ data.length - (newStart - dataStart));
+ dataStart = newStart;
+ }
+ }
+ /* Mark any missing data as invalid */
+ for (int i = dataEnd < dataStart ? dataStart : dataEnd;
+ i < newDataIndex; i++)
+ data[i - dataStart] = -1;
- /* If we receive a count less than the old count, we assume the old
- data is invalid */
- dataEnd = newEnd;
+ /* If we receive a count less than the old count, we assume the old
+ data is invalid */
+ dataEnd = newEnd;
}
/* Data received containing NREADINGS samples from messageId * NREADINGS
onwards */
void update(int messageId, int readings[]) {
- int start = messageId * Constants.NREADINGS;
- setEnd(start, start + Constants.NREADINGS);
- for (int i = 0; i < readings.length; i++)
- data[start - dataStart + i] = readings[i];
+ int start = messageId * Constants.NREADINGS;
+ setEnd(start, start + Constants.NREADINGS);
+ for (int i = 0; i < readings.length; i++)
+ data[start - dataStart + i] = readings[i];
}
/* Return value of sample x, or -1 for missing data */
int getData(int x) {
- if (x < dataStart || x >= dataEnd)
- return -1;
- else
- return data[x - dataStart];
+ if (x < dataStart || x >= dataEnd)
+ return -1;
+ else
+ return data[x - dataStart];
}
/* Return number of last known sample */
int maxX() {
- return dataEnd - 1;
+ return dataEnd - 1;
}
}
/* Main entry point */
void run() {
- data = new Data(this);
- window = new Window(this);
- window.setup();
- mote = new MoteIF(PrintStreamMessenger.err);
- mote.registerListener(new OscilloscopeMsg(), this);
+ data = new Data(this);
+ window = new Window(this);
+ window.setup();
+ mote = new MoteIF(PrintStreamMessenger.err);
+ mote.registerListener(new OscilloscopeMsg(), this);
}
/* The data object has informed us that nodeId is a previously unknown
mote. Update the GUI. */
void newNode(int nodeId) {
- window.newNode(nodeId);
+ window.newNode(nodeId);
}
synchronized public void messageReceived(int dest_addr, Message msg) {
- if (msg instanceof OscilloscopeMsg) {
- OscilloscopeMsg omsg = (OscilloscopeMsg)msg;
+ if (msg instanceof OscilloscopeMsg) {
+ OscilloscopeMsg omsg = (OscilloscopeMsg)msg;
- /* Update interval and mote data */
- periodUpdate(omsg.get_version(), omsg.get_interval());
- data.update(omsg.get_id(), omsg.get_count(), omsg.get_readings());
+ /* Update interval and mote data */
+ periodUpdate(omsg.get_version(), omsg.get_interval());
+ data.update(omsg.get_id(), omsg.get_count(), omsg.get_readings());
- /* Inform the GUI that new data showed up */
- window.newData();
- }
+ /* Inform the GUI that new data showed up */
+ window.newData();
+ }
}
/* A potentially new version and interval has been received from the
mote */
void periodUpdate(int moteVersion, int moteInterval) {
- if (moteVersion > version) {
- /* It's new. Update our vision of the interval. */
- version = moteVersion;
- interval = moteInterval;
- window.updateSamplePeriod();
- }
- else if (moteVersion < version) {
- /* It's old. Update the mote's vision of the interval. */
- sendInterval();
- }
+ if (moteVersion > version) {
+ /* It's new. Update our vision of the interval. */
+ version = moteVersion;
+ interval = moteInterval;
+ window.updateSamplePeriod();
+ }
+ else if (moteVersion < version) {
+ /* It's old. Update the mote's vision of the interval. */
+ sendInterval();
+ }
}
/* The user wants to set the interval to newPeriod. Refuse bogus values
and return false, or accept the change, broadcast it, and return
true */
synchronized boolean setInterval(int newPeriod) {
- if (newPeriod < 1 || newPeriod > 65535)
- return false;
- interval = newPeriod;
- version++;
- sendInterval();
- return true;
+ if (newPeriod < 1 || newPeriod > 65535)
+ return false;
+ interval = newPeriod;
+ version++;
+ sendInterval();
+ return true;
}
/* Broadcast a version+interval message. */
void sendInterval() {
- OscilloscopeMsg omsg = new OscilloscopeMsg();
-
- omsg.set_version(version);
- omsg.set_interval(interval);
- try {
- mote.send(MoteIF.TOS_BCAST_ADDR, omsg);
- }
- catch (IOException e) {
- window.error("Cannot send message to mote");
- }
+ OscilloscopeMsg omsg = new OscilloscopeMsg();
+
+ omsg.set_version(version);
+ omsg.set_interval(interval);
+ try {
+ mote.send(MoteIF.TOS_BCAST_ADDR, omsg);
+ }
+ catch (IOException e) {
+ window.error("Cannot send message to mote");
+ }
}
/* User wants to clear all data. */
void clear() {
- data = new Data(this);
+ data = new Data(this);
}
public static void main(String[] args) {
- Oscilloscope me = new Oscilloscope();
- me.run();
+ Oscilloscope me = new Oscilloscope();
+ me.run();
}
}
JFrame frame;
Window(Oscilloscope parent) {
- this.parent = parent;
+ this.parent = parent;
}
/* A model for the mote table, and general utility operations on the mote
list */
class MoteTableModel extends AbstractTableModel {
- private ArrayList motes = new ArrayList();
- private ArrayList colors = new ArrayList();
-
- /* Initial mote colors cycle through this list. Add more colors if
- you want. */
- private Color[] cycle = {
- Color.RED, Color.WHITE, Color.GREEN, Color.MAGENTA,
- Color.YELLOW, Color.GRAY, Color.YELLOW
- };
- int cycleIndex;
-
- /* TableModel methods for achieving our table appearance */
- public String getColumnName(int col) {
- if (col == 0)
- return "Mote";
- else
- return "Color";
- }
- public int getColumnCount() { return 2; }
- public synchronized int getRowCount() { return motes.size(); }
- public synchronized Object getValueAt(int row, int col) {
- if (col == 0)
- return motes.get(row);
- else
- return colors.get(row);
- }
+ private ArrayList motes = new ArrayList();
+ private ArrayList colors = new ArrayList();
+
+ /* Initial mote colors cycle through this list. Add more colors if
+ you want. */
+ private Color[] cycle = {
+ Color.RED, Color.WHITE, Color.GREEN, Color.MAGENTA,
+ Color.YELLOW, Color.GRAY, Color.YELLOW
+ };
+ int cycleIndex;
+
+ /* TableModel methods for achieving our table appearance */
+ public String getColumnName(int col) {
+ if (col == 0) {
+ return "Mote";
+ }
+ else {
+ return "Color";
+ }
+ }
+ public int getColumnCount() { return 2; }
+ public synchronized int getRowCount() { return motes.size(); }
+ public synchronized Object getValueAt(int row, int col) {
+ if (col == 0) {
+ return motes.get(row);
+ }
+ else {
+ return colors.get(row);
+ }
+ }
public Class getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
- public boolean isCellEditable(int row, int col) { return col == 1; }
+ public boolean isCellEditable(int row, int col) { return col == 1; }
public synchronized void setValueAt(Object value, int row, int col) {
- colors.set(row, value);
+ colors.set(row, value);
fireTableCellUpdated(row, col);
- graph.repaint();
+ graph.repaint();
}
- /* Return mote id of i'th mote */
- int get(int i) { return ((Integer)motes.get(i)).intValue(); }
-
- /* Return color of i'th mote */
- Color getColor(int i) { return (Color)colors.get(i); }
-
- /* Return number of motes */
- int size() { return motes.size(); }
-
- /* Add a new mote */
- synchronized void newNode(int nodeId) {
- /* Shock, horror. No binary search. */
- int i, len = motes.size();
-
- for (i = 0; ; i++)
- if (i == len || nodeId < get(i)) {
- motes.add(i, new Integer(nodeId));
- // Cycle through a set of initial colors
- colors.add(i, cycle[cycleIndex++ % cycle.length]);
- break;
- }
- fireTableRowsInserted(i, i);
- }
-
- /* Remove all motes */
- void clear() {
- motes = new ArrayList();
- colors = new ArrayList();
- fireTableDataChanged();
- }
+ /* Return mote id of i'th mote */
+ int get(int i) { return ((Integer)motes.get(i)).intValue(); }
+
+ /* Return color of i'th mote */
+ Color getColor(int i) { return (Color)colors.get(i); }
+
+ /* Return number of motes */
+ int size() { return motes.size(); }
+
+ /* Add a new mote */
+ synchronized void newNode(int nodeId) {
+ /* Shock, horror. No binary search. */
+ int i, len = motes.size();
+
+ for (i = 0; ; i++)
+ if (i == len || nodeId < get(i)) {
+ motes.add(i, new Integer(nodeId));
+ // Cycle through a set of initial colors
+ colors.add(i, cycle[cycleIndex++ % cycle.length]);
+ break;
+ }
+ fireTableRowsInserted(i, i);
+ }
+
+ /* Remove all motes */
+ void clear() {
+ motes = new ArrayList();
+ colors = new ArrayList();
+ fireTableDataChanged();
+ }
}
/* A simple full-color cell */
static class MoteColor extends JLabel implements TableCellRenderer {
- public MoteColor() { setOpaque(true); }
- public Component getTableCellRendererComponent
- (JTable table, Object color,
- boolean isSelected, boolean hasFocus, int row, int column) {
- setBackground((Color)color);
- return this;
- }
+ public MoteColor() { setOpaque(true); }
+ public Component getTableCellRendererComponent
+ (JTable table, Object color,
+ boolean isSelected, boolean hasFocus, int row, int column) {
+ setBackground((Color)color);
+ return this;
+ }
}
/* Convenience methods for making buttons, labels and textfields.
Simplifies code and ensures a consistent style. */
JButton makeButton(String label, ActionListener action) {
- JButton button = new JButton();
+ JButton button = new JButton();
button.setText(label);
button.setFont(boldFont);
- button.addActionListener(action);
- return button;
+ button.addActionListener(action);
+ return button;
}
JLabel makeLabel(String txt, int alignment) {
- JLabel label = new JLabel(txt, alignment);
- label.setFont(boldFont);
- return label;
+ JLabel label = new JLabel(txt, alignment);
+ label.setFont(boldFont);
+ return label;
}
JLabel makeSmallLabel(String txt, int alignment) {
- JLabel label = new JLabel(txt, alignment);
- label.setFont(smallFont);
- return label;
+ JLabel label = new JLabel(txt, alignment);
+ label.setFont(smallFont);
+ return label;
}
JTextField makeTextField(int columns, ActionListener action) {
- JTextField tf = new JTextField(columns);
- tf.setFont(normalFont);
- tf.setMaximumSize(tf.getPreferredSize());
- tf.addActionListener(action);
- return tf;
+ JTextField tf = new JTextField(columns);
+ tf.setFont(normalFont);
+ tf.setMaximumSize(tf.getPreferredSize());
+ tf.addActionListener(action);
+ return tf;
}
/* Build the GUI */
void setup() {
- JPanel main = new JPanel(new BorderLayout());
-
- main.setMinimumSize(new Dimension(500, 250));
- main.setPreferredSize(new Dimension(800, 400));
-
- // Three panels: mote list, graph, controls
- moteListModel = new MoteTableModel();
- JTable moteList = new JTable(moteListModel);
- moteList.setDefaultRenderer(Color.class, new MoteColor());
- moteList.setDefaultEditor(Color.class, new ColorCellEditor("Pick Mote Color"));
- moteList.setPreferredScrollableViewportSize(new Dimension(100, 400));
- JScrollPane motePanel = new JScrollPane();
- motePanel.getViewport().add(moteList, null);
- main.add(motePanel, BorderLayout.WEST);
-
- graph = new Graph(this);
- main.add(graph, BorderLayout.CENTER);
-
- // Controls. Organised using box layouts.
-
- // Sample period.
- JLabel sampleLabel = makeLabel("Sample period (ms):", JLabel.RIGHT);
- sampleText = makeTextField(6, new ActionListener() {
- public void actionPerformed(ActionEvent e) { setSamplePeriod(); }
- } );
- updateSamplePeriod();
-
- // Clear data.
- JButton clearButton = makeButton("Clear data", new ActionListener() {
- public void actionPerformed(ActionEvent e) { clearData(); }
- } );
-
- // Adjust X-axis zoom.
- Box xControl = new Box(BoxLayout.Y_AXIS);
- xLabel = makeLabel("", JLabel.CENTER);
- final JSlider xSlider = new JSlider(JSlider.HORIZONTAL, 0, 8, graph.scale);
- Hashtable xTable = new Hashtable();
- for (int i = 0; i <= 8; i += 2)
- xTable.put(new Integer(i),
- makeSmallLabel("" + (Graph.MIN_WIDTH << i),
- JLabel.CENTER));
- xSlider.setLabelTable(xTable);
- xSlider.setPaintLabels(true);
- graph.updateXLabel();
- graph.setScale(graph.scale);
- xSlider.addChangeListener(new ChangeListener() {
- public void stateChanged(ChangeEvent e) {
- //if (!xSlider.getValueIsAdjusting())
- graph.setScale((int)xSlider.getValue());
- }
- });
- xControl.add(xLabel);
- xControl.add(xSlider);
-
- // Adjust Y-axis range.
- JLabel yLabel = makeLabel("Y:", JLabel.RIGHT);
- yText = makeTextField(12, new ActionListener() {
- public void actionPerformed(ActionEvent e) { setYAxis(); }
- } );
- yText.setText(graph.gy0 + " - " + graph.gy1);
-
- Box controls = new Box(BoxLayout.X_AXIS);
- controls.add(clearButton);
- controls.add(Box.createHorizontalGlue());
- controls.add(Box.createRigidArea(new Dimension(20, 0)));
- controls.add(sampleLabel);
- controls.add(sampleText);
- controls.add(Box.createHorizontalGlue());
- controls.add(Box.createRigidArea(new Dimension(20, 0)));
- controls.add(xControl);
- controls.add(yLabel);
- controls.add(yText);
- main.add(controls, BorderLayout.SOUTH);
-
- // The frame part
- frame = new JFrame("Oscilloscope");
- frame.setSize(main.getPreferredSize());
- frame.getContentPane().add(main);
- frame.setVisible(true);
- frame.addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) { System.exit(0); }
- });
+ JPanel main = new JPanel(new BorderLayout());
+
+ main.setMinimumSize(new Dimension(500, 250));
+ main.setPreferredSize(new Dimension(800, 400));
+
+ // Three panels: mote list, graph, controls
+ moteListModel = new MoteTableModel();
+ JTable moteList = new JTable(moteListModel);
+ moteList.setDefaultRenderer(Color.class, new MoteColor());
+ moteList.setDefaultEditor(Color.class, new ColorCellEditor("Pick Mote Color"));
+ moteList.setPreferredScrollableViewportSize(new Dimension(100, 400));
+ JScrollPane motePanel = new JScrollPane();
+ motePanel.getViewport().add(moteList, null);
+ main.add(motePanel, BorderLayout.WEST);
+
+ graph = new Graph(this);
+ main.add(graph, BorderLayout.CENTER);
+
+ // Controls. Organised using box layouts.
+
+ // Sample period.
+ JLabel sampleLabel = makeLabel("Sample period (ms):", JLabel.RIGHT);
+ sampleText = makeTextField(6, new ActionListener() {
+ public void actionPerformed(ActionEvent e) { setSamplePeriod(); }
+ } );
+ updateSamplePeriod();
+
+ // Clear data.
+ JButton clearButton = makeButton("Clear data", new ActionListener() {
+ public void actionPerformed(ActionEvent e) { clearData(); }
+ } );
+
+ // Adjust X-axis zoom.
+ Box xControl = new Box(BoxLayout.Y_AXIS);
+ xLabel = makeLabel("", JLabel.CENTER);
+ final JSlider xSlider = new JSlider(JSlider.HORIZONTAL, 0, 8, graph.scale);
+ Hashtable xTable = new Hashtable();
+ for (int i = 0; i <= 8; i += 2)
+ xTable.put(new Integer(i),
+ makeSmallLabel("" + (Graph.MIN_WIDTH << i),
+ JLabel.CENTER));
+ xSlider.setLabelTable(xTable);
+ xSlider.setPaintLabels(true);
+ graph.updateXLabel();
+ graph.setScale(graph.scale);
+ xSlider.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent e) {
+ //if (!xSlider.getValueIsAdjusting())
+ graph.setScale((int)xSlider.getValue());
+ }
+ });
+ xControl.add(xLabel);
+ xControl.add(xSlider);
+
+ // Adjust Y-axis range.
+ JLabel yLabel = makeLabel("Y:", JLabel.RIGHT);
+ yText = makeTextField(12, new ActionListener() {
+ public void actionPerformed(ActionEvent e) { setYAxis(); }
+ } );
+ yText.setText(graph.gy0 + " - " + graph.gy1);
+
+ Box controls = new Box(BoxLayout.X_AXIS);
+ controls.add(clearButton);
+ controls.add(Box.createHorizontalGlue());
+ controls.add(Box.createRigidArea(new Dimension(20, 0)));
+ controls.add(sampleLabel);
+ controls.add(sampleText);
+ controls.add(Box.createHorizontalGlue());
+ controls.add(Box.createRigidArea(new Dimension(20, 0)));
+ controls.add(xControl);
+ controls.add(yLabel);
+ controls.add(yText);
+ main.add(controls, BorderLayout.SOUTH);
+
+ // The frame part
+ frame = new JFrame("Oscilloscope");
+ frame.setSize(main.getPreferredSize());
+ frame.getContentPane().add(main);
+ frame.setVisible(true);
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) { System.exit(0); }
+ });
}
/* User operation: clear data */
void clearData() {
- synchronized (parent) {
- moteListModel.clear();
- parent.clear();
- graph.newData();
- }
+ synchronized (parent) {
+ moteListModel.clear();
+ parent.clear();
+ graph.newData();
+ }
}
/* User operation: set Y-axis range. */
void setYAxis() {
- String val = yText.getText();
-
- try {
- int dash = val.indexOf('-');
- if (dash >= 0) {
- String min = val.substring(0, dash).trim();
- String max = val.substring(dash + 1).trim();
-
- if (!graph.setYAxis(Integer.parseInt(min), Integer.parseInt(max)))
- error("Invalid range " + min + " - " + max + " (expected values between 0 and 65535)");
- return;
- }
- }
- catch (NumberFormatException e) { }
- error("Invalid range " + val + " (expected NN-MM)");
+ String val = yText.getText();
+
+ try {
+ int dash = val.indexOf('-');
+ if (dash >= 0) {
+ String min = val.substring(0, dash).trim();
+ String max = val.substring(dash + 1).trim();
+
+ if (!graph.setYAxis(Integer.parseInt(min), Integer.parseInt(max)))
+ error("Invalid range " + min + " - " + max + " (expected values between 0 and 65535)");
+ return;
+ }
+ }
+ catch (NumberFormatException e) { }
+ error("Invalid range " + val + " (expected NN-MM)");
}
/* User operation: set sample period. */
void setSamplePeriod() {
- String periodS = sampleText.getText().trim();
- try {
- int newPeriod = Integer.parseInt(periodS);
- if (parent.setInterval(newPeriod))
- return;
- }
- catch (NumberFormatException e) { }
- error("Invalid sample period " + periodS);
+ String periodS = sampleText.getText().trim();
+ try {
+ int newPeriod = Integer.parseInt(periodS);
+ if (parent.setInterval(newPeriod)) {
+ return;
+ }
+ }
+ catch (NumberFormatException e) { }
+ error("Invalid sample period " + periodS);
}
/* Notification: sample period changed. */
void updateSamplePeriod() {
- sampleText.setText("" + parent.interval);
+ sampleText.setText("" + parent.interval);
}
/* Notification: new node. */
void newNode(int nodeId) {
- moteListModel.newNode(nodeId);
+ moteListModel.newNode(nodeId);
}
/* Notification: new data. */
void newData() {
- graph.newData();
+ graph.newData();
}
void error(String msg) {
- JOptionPane.showMessageDialog(frame, msg, "Error",
- JOptionPane.ERROR_MESSAGE);
+ JOptionPane.showMessageDialog(frame, msg, "Error",
+ JOptionPane.ERROR_MESSAGE);
}
}