package com.rle.monitor; import java.awt.event.*; import java.io.*; import javax.comm.*; import javax.swing.*; import javax.swing.event.*; /* * RLE Surface Crack Detector Graphing Software * * Copyright (C) 2002 RLE Technologies * For more information visit http://www.rletech.com/ * * 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. */ /** * @author Andy Goth * @author Eric Peterson * @author Matt Lane * @version 0.1 */ /* * TODO: * Make size, skip, and baseLen configurable * Fix the auto offset stuff */ /** Connection to a Scanner device. */ public class Buffer implements EchoListener, SampleListener { private Display display; /* Display data is sent to */ private Scanner scanner; /* Data source */ private int size = 10364; /* Size of buffer */ private int index = 0; /* Insertion index */ private int start = size; /* Index of first valid value */ private int data[] = new int[size]; /* Sample data */ private int skip = 0; /* Interval between samples */ private int numSkipped = 0; /* Skipped samples so far */ private int skipAccum = 0; /* Sum of skipped samples */ private String portName; /* System's name for port */ private int offset = -1; /* Scanner's offset */ private int gain = -1; /* Scanner's gain */ private int threshhold = -1; /* Scanner's threshhold */ private EventListenerList paramListeners = new EventListenerList(); private int baseLen = 5182; /* Samples for baseline */ private float baseline = -1f; /* Baseline * baseSize */ private int time = baseLen / 2; /* Timer for offset updates */ /* TODO: instead of adj, use buffer.setOffset */ private int adj = 0; /** Constructor. */ public Buffer(String portName) {this.portName = portName;} /** Returns the port's name. */ public String getPortName() {return portName;} /** Sets the port's name. */ public void setPortName(String portName) { if (scanner != null) throw new UnsupportedOperationException( "Port must first be closed"); this.portName = portName; } /** Returns the associated display. */ public Display getDisplay() {return display;} /** Sets the associated display. */ public void setDisplay(Display display) {this.display = display;} /** Returns the interval between samples. */ public int getSkip() {return skip;} /** Sets the interval between samples. */ public void setSkip(int skip) { if (skip < 0) throw new IllegalArgumentException("Out of bounds"); this.skip = skip; } /** Returns the size of the buffer. */ public int getSize() {return size;} /** Adjusts the size of the buffer. */ public void setSize(int newSize) { if (newSize == size) return; if (newSize < Bounds.MIN_WIDTH) throw new IllegalArgumentException("Out of bounds"); int newData[] = new int[newSize]; int begin, offset, count; if (newSize > size || size - start <= newSize) { /* Copy all samples */ begin = start; offset = newSize - start; count = size - start; start += newSize - size; } else { /* Drop older samples */ begin = size - newSize; offset = 0; count = newSize; start = 0; } for (int i = begin; i < count; i++) newData[i + offset] = getSample(i); index = newSize; } /** Returns true if the connection is opened. */ public boolean getOpened() {return scanner != null;} /** Opens a connection to the scanner. */ public void open() throws IOException { if (scanner != null) throw new UnsupportedOperationException( "Scanner already opened"); //scanner = new Serial(); /* Uncomment this! */ scanner = new Emulator(); scanner.setEchoListener(this); scanner.setSampleListener(this); scanner.open(portName); Timer timer = new javax.swing.Timer(0, new ActionListener() { public void actionPerformed(ActionEvent e) { queryThreshhold(); } }); timer.setInitialDelay(100); timer.setRepeats(false); timer.start(); } /** Cleanup. */ public void close() { if (scanner == null) throw new UnsupportedOperationException( "Scanner already closed"); try { scanner.close(); scanner = null; } catch (IOException e) {} } public int getOffset() {return offset;} public void queryOffset() {try {scanner.queryOffset();} catch (IOException e) {}} public void setOffset(int o) {try {scanner.setOffset(o); offset = o;} catch (IOException e) {}} public int getGain() {return gain;} public void queryGain() {try {scanner.queryGain();} catch (IOException e) {}} public void setGain(int g) {try {scanner.setGain(g); gain = g;} catch (IOException e) {}} public int getThreshhold() {return threshhold;} public void queryThreshhold() {try {scanner.queryThreshhold();} catch (IOException e) {}} public void setThreshhold(int t) {try {scanner.setThreshhold(t); threshhold = t;} catch(IOException e){}} /** Registers a new parameter listener. */ public void addParamListener(ParamListener l) { paramListeners.add(ParamListener.class, l); } /** Unregisters a parameter listener. */ public void removeSelectionListener(SelectionListener l) { paramListeners.remove(ParamListener.class, l); } /** Sends out notifications that the offset changed. */ protected void fireOffsetChange() { Object[] listeners = paramListeners.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] != ParamListener.class) continue; ((ParamListener)listeners[i + 1]).offsetChanged(offset); } } /** Sends out notifications that the gain changed. */ protected void fireGainChange() { Object[] listeners = paramListeners.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] != ParamListener.class) continue; ((ParamListener)listeners[i + 1]).gainChanged(gain); } } /** Sends out notifications that the threshhold changed. */ protected void fireThreshholdChange() { Object[] listeners = paramListeners.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] != ParamListener.class) continue; ((ParamListener)listeners[i + 1]). threshholdChanged(threshhold); } } /** Echo handler. */ public void echo(int type, int val) { switch (type) { case Scanner.OFFSET: if (val == offset) break; offset = val; fireOffsetChange(); break; case Scanner.GAIN: if (val == gain) break; gain = val; fireGainChange(); break; /* case Scanner.AUTO_OFFSET: break; case Scanner.ALARM: break; case Scanner.LED: break; */ case Scanner.THRESHHOLD: if (val == threshhold) break; threshhold = val; fireThreshholdChange(); /* break; case Scanner.QUERY:*/ } } /** Sample handler. */ public void sample(int val) { if (display == null || !display.getRunning()) return; if (skip != 0) { if (numSkipped < skip) { numSkipped++; skipAccum += val; return; } numSkipped = 0; val = (skipAccum + val) / (skip + 1); skipAccum = 0; } if (size - start == baseLen && baseline < 0f) { /* Calculate the initial baseline */ baseline = 0f; for (int i = start; i < size; i++) baseline += getSample(i); } else if (size - start >= baseLen) { /* Update the baseline with the new value */ int bl = getBaseline(); if (bl < 150 || bl > 170) { if (time >= baseLen) { adj += 160 - bl; time = 0; } else time++; } else { time = baseLen / 2; } /* TODO: Change this next line to setOffset(adj); * This means converting a sample value to an offset * value, taking the current gain into account. */ val += adj; if (val < 0) val = 0; else if (val > 255) val = 255; baseline += -getSample(size - baseLen) + val; } /* else there aren't enough samples to establish a baseline */ /* Store the value */ synchronized (data) { data[index++] = val; if (index == size) index = 0; if (start > 0) start--; } } /** Returns the kth sample. */ public int getSample(int k) { if (k < start || k >= size) throw new IllegalArgumentException("Out of bounds"); k += index; if (k >= size) k -= size; return data[k]; } /** Returns the current baseline. */ public int getBaseline() {return (int)(baseline / baseLen);} /** Returns the index of the first sample. */ public int getStart() {return start;} }