-Added a class to serve up results to atom. A matching client C++ class should follow shortly.
-Generally beautified code
git-svn-id: https://robotics.mvla.net/svn/frc971/2013/trunk/src@4148 f308d9b7-e957-4cde-b6ac-9a88185e7312
diff --git a/971CV/src/org/frc971/AccepterThread.java b/971CV/src/org/frc971/AccepterThread.java
new file mode 100644
index 0000000..e6cd5dd
--- /dev/null
+++ b/971CV/src/org/frc971/AccepterThread.java
@@ -0,0 +1,153 @@
+/**
+ *
+ */
+package org.frc971;
+
+/**
+ * @author daniel
+ * Accepts clients for data server
+ */
+
+import java.io.IOException;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+public class AccepterThread extends Thread {
+
+ private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+
+ private ServerSocketChannel sock;
+
+ private List<SocketChannel> connected = new ArrayList<SocketChannel>();
+
+ /* Holds overflow data when socket's send buffer gets full, so that
+ * thread can continue running.
+ */
+ private Map<SocketChannel, ByteBuffer> toSend;
+ /* Keeps track of how many times a write operation on a socket
+ * has failed because it's buffer was full.
+ */
+ private Map<SocketChannel, Integer> failedAttempts; //doesn't like primitive types
+
+ /** Helper function to completely erase a peer from
+ * all three lists and maps that might contain it.
+ */
+ private void erasePeer(SocketChannel peer) {
+ connected.remove(peer);
+ toSend.remove(peer);
+ failedAttempts.remove(peer);
+ }
+
+ /** Constructor
+ *
+ * @param sock is the ServerSocketChannel that you want to monitor
+ */
+ public AccepterThread(ServerSocketChannel sock) {
+ super("Accepter Thread");
+ setPriority(3); //lowish priority so Image Processor overrides it
+ this.sock = sock;
+ start();
+ }
+
+ /** Runs in separate thread. Continually accepts new connections. */
+ public void run() {
+ SocketChannel clientSock;
+ while (true) {
+ try {
+ clientSock = sock.accept();
+ //our writes must not block
+ clientSock.configureBlocking(false);
+ connected.add(clientSock);
+ }
+ catch (IOException e) {
+ LOG.warning("Socket accept failed.");
+ }
+ }
+ }
+
+ /** Sends a message to all currently connected clients.
+ *
+ * @param message is the message that you want to send.
+ */
+ public void sendtoAll(ByteBuffer message) {
+ /* Copy our connected list, so we don't have
+ * to hold our lock forever if the writes block.
+ */
+ List<SocketChannel> connectedTemp = new ArrayList<SocketChannel>();
+ for (SocketChannel channel : connected) {
+ connectedTemp.add(channel);
+ }
+
+ int result;
+ for (SocketChannel conn : connectedTemp) {
+ try {
+
+ /** If this socket has data from the
+ * last send operation still waiting to be
+ * sent, send this instead of our original
+ * message. Since we generally want only
+ * current data, our original message will
+ * not be missed. However, it is imperative
+ * that we finish our pending transmission,
+ * because an incomplete transmission could
+ * leave a client thread somewhere blocking
+ * indefinitely.
+ */
+ if (toSend.containsKey(conn)) {
+ message = toSend.get(conn);
+ }
+
+ result = conn.write(message);
+
+ /*if our send buffer is full, store our message away
+ * so we can try again later without halting the thread.
+ */
+ if (message.remaining() > 0) {
+ toSend.put(conn, message);
+ //check and update our count of failed send attempts
+ if (failedAttempts.containsKey(conn)) {
+ int failures = failedAttempts.get(conn);
+ ++failures;
+ if (failures >= 100) {
+ //Socket has become dysfunctional
+ LOG.info("Write would have blocked 100 times. Assuming peer disconect.");
+ erasePeer(conn);
+ }
+ failedAttempts.put(conn, failures);
+ }
+ else {
+ failedAttempts.put(conn, 1);
+ }
+ }
+
+ if (result == -1) {
+ //The write failed. This is probably because the client disconnected.
+ LOG.info("Write returned -1. Client has probably disconnected.");
+ erasePeer(conn);
+ }
+ }
+ catch (IOException e) {
+ //The write failed. This is probably because the client disconnected.
+ LOG.info("Write threw IOException. Client has probably disconnected.");
+ erasePeer(conn);
+ }
+ }
+ }
+
+ /** Overloaded sendtoAll method for byte arrays. */
+ public void sendtoAll(byte[] message) {
+ sendtoAll(ByteBuffer.wrap(message));
+ }
+
+ /** Overloaded sendtoAll method for Strings. */
+ public void sendtoAll(String message) {
+ sendtoAll(message.getBytes());
+ }
+}
diff --git a/971CV/src/org/frc971/DebugServerRun.java b/971CV/src/org/frc971/DebugServerRun.java
index c8146b1..0f60665 100644
--- a/971CV/src/org/frc971/DebugServerRun.java
+++ b/971CV/src/org/frc971/DebugServerRun.java
@@ -1,27 +1,14 @@
package org.frc971;
import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.InterruptedIOException;
-import java.io.PrintWriter;
import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.SocketException;
import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
@@ -40,51 +27,8 @@
private ServerSocketChannel sock;
private SocketChannel client;
-
- private BufferedReader sock_in;
- private PrintWriter sock_out;
-
- private String ReadtoBoundary(String boundary) {
- //reads from socket until it encounters a specific character combination
- //if boundary is null, it reads until it runs out of data
- ByteBuffer recvd = ByteBuffer.allocate(1024);
- StringBuilder sb = new StringBuilder();
- String message = "";
- try {
- int ret = 0;
- while (ret != -1) {
- ret = client.read(recvd);
- //System.out.println(ret);
- if (ret == 0) {
- //finished receiving
- message = sb.toString();
- if (boundary == null)
- break;
- }
- else {
- for (int i = 0; i < recvd.capacity() - recvd.remaining(); i++) {
- sb.append((char)recvd.get(i));
- }
- recvd.clear();
- if (boundary != null) {
- if (sb.toString().contains(boundary)) {
- message = sb.toString();
- break;
- }
- else {
- continue;
- }
- }
- }
- }
- }
- catch (IOException e) {
- LOG.severe("Socket read failed.");
- return null;
- }
- return message;
- }
+ /** Constructs a formatted boundary header from a timestamp and content length. */
private ByteBuffer CreateTransmission(long content_length, double timestamp) {
StringBuilder ret = new StringBuilder();
ret.append("\r\n--boundarydonotcross\r\n");
@@ -97,8 +41,9 @@
ret.append("\r\n\r\n");
return ByteBuffer.wrap(ret.toString().getBytes());
}
+
+ /** Loop that pushes a data stream to the client. */
private void push() {
- //push data to client
try {
grabber.start();
}
@@ -116,6 +61,10 @@
try {
img = grabber.grab();
timestamp = System.currentTimeMillis();
+ /*We buffer through /dev/shm, just to make the conversion process easier.
+ * I know this is really ugly, but it works a lot better than what
+ * I was doing before, which segfaulted.
+ */
cvSaveImage("/dev/shm/DebugServerBuffer.jpg", img);
buff_file = new File("/dev/shm/DebugServerBuffer.jpg");
content_size = buff_file.length();
@@ -136,9 +85,7 @@
to_send.put(header);
to_send.put(bbuf);
to_send.rewind();
- while (to_send.remaining() > 0) {
- client.write(to_send);
- }
+ SocketCommon.sendAll(client, to_send);
}
catch (Exception e) {
LOG.warning("Could not grab frame.");
@@ -146,35 +93,26 @@
}
}
}
-
- public void Connect() throws IOException {
- client = sock.accept();
- client.configureBlocking(false);
- //sock_in = new BufferedReader(new InputStreamReader(client.socket().getInputStream()));
- //sock_out = new PrintWriter(client.socket().getOutputStream(), true);
- //we are now connected to our client. Wait for them to send us a header.
- LOG.info("Reading headers...");
- ReadtoBoundary("\r\n\r\n");
- //send one back
- LOG.info("Writing headers...");
- String ending = "donotcross\r\n";
- ByteBuffer buff = ByteBuffer.wrap(ending.getBytes());
- while (buff.remaining() > 0) {
- client.write(buff);
- }
- }
-
+ /** Constructor to start the server and bind it to a port. */
public DebugServerRun(final int port) throws IOException {
sock = ServerSocketChannel.open();
sock.socket().bind(new InetSocketAddress(9714));
+ client = sock.accept();
+ client.configureBlocking(false);
+ //we are now connected to our client. Wait for them to send us a header.
+ LOG.info("Reading headers...");
+ SocketCommon.readtoBoundary(client, "\r\n\r\n");
+ //send one back
+ LOG.info("Writing headers...");
+ SocketCommon.sendAll(client, "donotcross\r\n");
}
- public static void main(final String args[]) throws IOException{
+ /** Runs the server, and concurrently starts the vision processor with -vision flag. */
+ public static void main(final String args[]) throws IOException {
//main function for server
-
//set logger to log everything
LOG.setLevel(Level.ALL);
try {
- LogHandler handler = new LogHandler("../src/org/frc971/ds_vision.log");
+ LogHandler handler = new LogHandler("ds_vision.log");
TimeFormatter formatter = new TimeFormatter();
handler.setFormatter(formatter);
LOG.addHandler(handler);
@@ -183,9 +121,12 @@
System.err.println("Warning: Logging initialization failed.");
}
+ if (args[0].equals("-vision")) {
+ LOG.info("Starting vision processor.");
+ new TestClient();
+ }
+
DebugServerRun server = new DebugServerRun(9714);
- new TestClient();
- server.Connect();
server.push();
}
}
diff --git a/971CV/src/org/frc971/HTTPClient.java b/971CV/src/org/frc971/HTTPClient.java
index 4c7d0af..cc694ef 100644
--- a/971CV/src/org/frc971/HTTPClient.java
+++ b/971CV/src/org/frc971/HTTPClient.java
@@ -2,28 +2,17 @@
//@author: daniel
-import static com.googlecode.javacv.cpp.opencv_highgui.cvEncodeImage;
-
import java.io.*;
import java.net.*;
import java.awt.image.BufferedImage;
-import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.ByteBuffer;
-import java.util.Iterator;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
-import javax.imageio.ImageReadParam;
-import javax.imageio.ImageReader;
-import javax.imageio.stream.ImageInputStream;
-
-import com.googlecode.javacv.cpp.opencv_core.CvArr;
-import com.googlecode.javacv.cpp.opencv_core.CvMat;
-import com.googlecode.javacv.cpp.opencv_core.IplImage;
import aos.ChannelImageGetter;
@@ -32,14 +21,10 @@
public class HTTPClient {
//Connects to HTTP Server on robot and receives images
- private final static boolean LOCAL_DEBUG = true;
+ /** whether or not to print debug messages to stdout. */
+ private final static boolean LOCAL_DEBUG = false;
private SocketChannel sock;
- private Socket core_sock;
-
-
- private BufferedReader sock_in;
- private PrintWriter sock_out;
private final String ATOM_IP = "192.168.0.137";
@@ -47,87 +32,37 @@
private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ /** Small helper method for printing debug messages to stdout. */
private void WriteDebug(String message) {
//small helper function to write debug messages
if (LOCAL_DEBUG)
LOG.info("LOCAL_DEBUG: " + message);
}
- private String ReadtoBoundary(String boundary) {
- //reads from socket until it encounters a specific character combination
- //if boundary is null, it reads until it runs out of data
- ByteBuffer recvd = ByteBuffer.allocate(1024);
- StringBuilder sb = new StringBuilder();
- String message = "";
- try {
- int ret;
- while ((ret = sock.read(recvd)) != -1) {
- if (ret == 0) {
- //finished receiving
- message = sb.toString();
- if (boundary == null)
- break;
- }
- else {
- for (int i = 0; i < recvd.capacity() - recvd.remaining(); i++) {
- sb.append((char)recvd.get(i));
- }
- recvd.clear();
- if (boundary != null) {
- if (sb.toString().contains(boundary)) {
- message = sb.toString();
- break;
- }
- else {
- continue;
- }
- }
- }
- }
- }
- catch (IOException e) {
- LOG.severe("Socket read failed.");
- return null;
- }
- return message;
+
+ /** the constructor, initializes connection, and sets up aos getter.
+ * @throws IOException */
+ public HTTPClient() throws IOException {
+ //Initialize socket connection to robot
+ sock = SocketChannel.open();
+ WriteDebug("Connecting to server at " + ATOM_IP);
+ sock.connect(new InetSocketAddress(ATOM_IP, 9714));
+ sock.configureBlocking(false);
+ //Write headers
+ //HTTPStreamer does not actually use the headers, so we can just write terminating chars.
+ WriteDebug("Writing headers...");
+ SocketCommon.sendAll(sock, "\r\n\r\n");
+ //Receive headers
+ WriteDebug("Reading headers...");
+ SocketCommon.readtoBoundary(sock, "donotcross\r\n");
+ WriteDebug("Now receiving data.");
+ cgetter = new ChannelImageGetter(sock);
}
- public HTTPClient() {
- //Initialize socket connection to robot
- try {
- sock = SocketChannel.open();
- core_sock = sock.socket();
- WriteDebug("Connecting to server at " + ATOM_IP);
- sock.connect(new InetSocketAddress(ATOM_IP, 9714));
- sock.configureBlocking(false);
- //sock_in = new BufferedReader(new InputStreamReader(core_sock.getInputStream()));
- //sock_out = new PrintWriter(core_sock.getOutputStream(), true);
- //Write headers
- //HTTPStreamer does not actually use the headers, so we can just write terminating chars.
- WriteDebug("Writing headers...");
- String ending = "\r\n\r\n";
- ByteBuffer header = ByteBuffer.wrap(ending.getBytes());
- while (header.remaining() > 0) {
- sock.write(header);
- }
- //Receive headers
- WriteDebug("Reading headers...");
- ReadtoBoundary("donotcross\r\n");
- WriteDebug("Now receiving data.");
- cgetter = new ChannelImageGetter(sock);
- }
- catch (UnknownHostException e) {
- LOG.severe("Invalid host.");
- System.exit(1);
- }
- catch (IOException e) {
- LOG.severe("Socket IO failed: " + e.getMessage());
- System.exit(2);
- }
-
- }
+ /** Grabs the most current frame from the HTTPStreamer stream.
+ * Returns a class instance with image and timestamp attributes. */
public ImageWithTimestamp GetFrame() {
- //Use Brian's code to extract an image and timestamp from raw server data.
ImageWithTimestamp final_image = new ImageWithTimestamp();
+ //Use Brian's code to extract an image and timestamp from raw server data.
ByteBuffer binary_image = cgetter.getJPEG();
//Decode ByteBuffer into an IplImage
byte[] b = new byte[binary_image.remaining()];
@@ -141,6 +76,7 @@
return final_image;
}
catch (IOException e) {
+ LOG.warning("Image processing failed: " + e.getMessage());
return null;
}
}
diff --git a/971CV/src/org/frc971/ImageWithTimestamp.java b/971CV/src/org/frc971/ImageWithTimestamp.java
index 38f6937..8b43818 100644
--- a/971CV/src/org/frc971/ImageWithTimestamp.java
+++ b/971CV/src/org/frc971/ImageWithTimestamp.java
@@ -2,6 +2,7 @@
import edu.wpi.first.wpijavacv.WPIColorImage;
+/** Small helper class for associating images and timestamps. */
public class ImageWithTimestamp {
WPIColorImage image;
double timestamp;
diff --git a/971CV/src/org/frc971/LogHandler.java b/971CV/src/org/frc971/LogHandler.java
index 59f74a9..fd486fb 100644
--- a/971CV/src/org/frc971/LogHandler.java
+++ b/971CV/src/org/frc971/LogHandler.java
@@ -12,13 +12,20 @@
/**
* @author daniel
- * logs data to custom files, using specific formatting.
+ *
*/
+
+/** Logs data to custom files, using specific formatting. */
public class LogHandler extends Handler {
private FileOutputStream ofstream;
PrintWriter writer;
+ /** Constructor for log handler.
+ *
+ * @param filename is the name of the file you want to log to.
+ * @throws FileNotFoundException if file cannot be opened or created.
+ */
public LogHandler (String filename) throws FileNotFoundException {
super();
@@ -34,6 +41,9 @@
/*Required methods*/
+ /** Is required by API. Writes a new message to the log.
+ * @param message is the message you want to log.
+ */
public void publish(LogRecord message) {
//record a message
if (!isLoggable(message)) {
@@ -42,9 +52,13 @@
}
writer.print(getFormatter().format(message)); //Formatter adds trailing \n
}
+
+ /** Is required by API. Flushes the writer. */
public void flush() {
writer.flush();
}
+
+ /** Is required by API. Closes logfile. */
public void close() throws SecurityException {
writer.close();
}
diff --git a/971CV/src/org/frc971/ResultSender.java b/971CV/src/org/frc971/ResultSender.java
new file mode 100644
index 0000000..897371d
--- /dev/null
+++ b/971CV/src/org/frc971/ResultSender.java
@@ -0,0 +1,53 @@
+/**
+ *
+ */
+package org.frc971;
+
+import java.io.IOException;
+
+import java.net.InetSocketAddress;
+
+import java.nio.channels.ServerSocketChannel;
+
+/**
+ * @author daniel
+ *
+ */
+
+/** Serves processing results back to the atom. */
+public class ResultSender {
+ private static final int PORT = 9715;
+
+ private ServerSocketChannel sock;
+
+ AccepterThread acceptor;
+
+ /** Constructor. Connects to a socket and starts the accepter thread. */
+ public ResultSender() throws IOException {
+ sock = ServerSocketChannel.open();
+ sock.socket().bind(new InetSocketAddress(PORT));
+
+ //start accepter thread
+ acceptor = new AccepterThread(sock);
+ }
+
+ /** Sends a new message of calculated attributes to the clients.
+ *
+ * @param azimuth is the calculated optimum azimuth for the shot.
+ * @param elevation is the calculated optimum elevation for the shot.
+ * @param range is the calculated optimum range for the shot.
+ */
+ public void send(double azimuth, double elevation, double range) {
+ //Formulate a message as a String similar to an HTTP header.
+ StringBuilder message = new StringBuilder();
+ message.append("\r\n--boundarydonotcross\r\n");
+ message.append("Azimuth: ");
+ message.append(azimuth);
+ message.append("\r\nElevation: ");
+ message.append(elevation);
+ message.append("\r\nRange: ");
+ message.append(range);
+
+ acceptor.sendtoAll(message.toString());
+ }
+}
diff --git a/971CV/src/org/frc971/SocketCommon.java b/971CV/src/org/frc971/SocketCommon.java
new file mode 100644
index 0000000..e49a82b
--- /dev/null
+++ b/971CV/src/org/frc971/SocketCommon.java
@@ -0,0 +1,89 @@
+/**
+ *
+ */
+package org.frc971;
+
+import java.io.IOException;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.logging.Logger;
+
+/**
+ * @author daniel
+ * Socket operations used by other classes
+ */
+public class SocketCommon {
+
+ private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+
+ /** Reads on a SocketStream until it finds a given character sequence. */
+ public static String readtoBoundary(SocketChannel sock, String boundary) {
+ //reads from socket until it encounters a specific character combination
+ //if boundary is null, it reads until it runs out of data
+ ByteBuffer recvd = ByteBuffer.allocate(1024);
+ StringBuilder sb = new StringBuilder();
+ String message = "";
+ try {
+ int ret = 0;
+ while (ret != -1) {
+ ret = sock.read(recvd);
+ //System.out.println(ret);
+ if (ret == 0) {
+ //finished receiving
+ message = sb.toString();
+ if (boundary == null)
+ break;
+ }
+ else {
+ for (int i = 0; i < recvd.capacity() - recvd.remaining(); i++) {
+ sb.append((char)recvd.get(i));
+ }
+ recvd.clear();
+ if (boundary != null) {
+ if (sb.toString().contains(boundary)) {
+ message = sb.toString();
+ break;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.severe("Socket read failed.");
+ return null;
+ }
+ return message;
+ }
+
+ /** Guarantees that large messages will be completely sent through a socket.
+ * @return Returns 0 for success, -1 for failure.
+ */
+ public static int sendAll(SocketChannel sock, ByteBuffer message) {
+ message.rewind();
+ while (message.remaining() > 0) {
+ try {
+ sock.write(message);
+ }
+ catch (IOException e) {
+ LOG.warning("Socket write failed.");
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ /** Overloaded method for sending a byte array. */
+ public static void sendAll(SocketChannel sock, byte[] message) {
+ ByteBuffer buff = ByteBuffer.wrap(message);
+ sendAll(sock, buff);
+ }
+
+ /** Overloaded method for sending a String. */
+ public static void sendAll(SocketChannel sock, String message) {
+ sendAll(sock, message.getBytes());
+ }
+}
diff --git a/971CV/src/org/frc971/TestClient.java b/971CV/src/org/frc971/TestClient.java
index fed5c27..926a817 100644
--- a/971CV/src/org/frc971/TestClient.java
+++ b/971CV/src/org/frc971/TestClient.java
@@ -5,13 +5,19 @@
/**
* @author daniel
- *
+ *
*/
+
+/** Small thread for running vision code concurrently with debug server. */
public class TestClient extends Thread {
+
+ /** Constructor to set up new thread. */
public TestClient() {
super("Test Client");
start();
}
+
+ /** Simple thread, runs the vision code. */
public void run() {
String[] args = {};
VisionTuner.main(args);
diff --git a/971CV/src/org/frc971/TestImageGetter.java b/971CV/src/org/frc971/TestImageGetter.java
index b0cf9b0..a61ed60 100644
--- a/971CV/src/org/frc971/TestImageGetter.java
+++ b/971CV/src/org/frc971/TestImageGetter.java
@@ -8,8 +8,6 @@
*
*/
-//get debug images for Java camera processor
-
import java.io.File;
import java.io.IOException;
@@ -19,12 +17,16 @@
import edu.wpi.first.wpijavacv.WPIColorImage;
+/** Get debug images for Java camera processor. */
public class TestImageGetter {
private String path_to_images;
private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ /** The names of our debugging images, without paths.
+ * The GetNext method should be used to get the first
+ * image, and not GetCurrent. */
final static String[] images = {"45in_DoubleGreen.jpg",
"57inLargeTarget_DoubleGreenBK.jpg",
"FullField_DoubleGreenBK3.jpg",
@@ -49,15 +51,26 @@
private WPIColorImage current_image = null;
+ /** Helper method to concatenate paths, similar to Python's os.path.join(). */
private String cocatenate_paths(String path1, String path2) {
if (path1.charAt(path1.length() - 1) == '/')
return path1 + path2;
else
return path1 + "/" + path2;
}
+
+ /** Constructor
+ *
+ * @param path_to_images is the path to the directory where our images are.
+ */
public TestImageGetter(String path_to_images) {
this.path_to_images = path_to_images;
}
+
+ /** Gets the next debugging image.
+ *
+ * @return Returns a WPIColorImage.
+ */
public WPIColorImage GetNext() {
image_index++;
if (image_index < images.length) {
@@ -75,6 +88,11 @@
image_index--;
return null;
}
+
+ /** Gets the previous debugging image.
+ *
+ * @return Returns a WPIColorImage.
+ */
public WPIColorImage GetPrev() {
image_index--;
if (image_index >= 0) {
@@ -92,6 +110,11 @@
image_index++;
return null;
}
+
+ /** Gets the current debugging image. This is vestigial, it is not longer used.
+ *
+ * @return Returns a WPIColorImage
+ */
public WPIColorImage GetCurrent() {
return current_image;
}
diff --git a/971CV/src/org/frc971/TimeFormatter.java b/971CV/src/org/frc971/TimeFormatter.java
index 9f46bd4..1bff96f 100644
--- a/971CV/src/org/frc971/TimeFormatter.java
+++ b/971CV/src/org/frc971/TimeFormatter.java
@@ -9,12 +9,20 @@
/**
* @author daniel
- * Formats log messages with adequate timestamp
+ *
*/
+
+/** Formats log messages with adequate timestamp. */
public class TimeFormatter extends Formatter{
+
+ /** Constructor, see Formatter. */
public TimeFormatter() {
super();
}
+
+ /** Format a message in the propper way.
+ * @return Includes time, name of logger, level and message.
+ */
public String format(LogRecord message) {
//we need to include the date and time in our message
StringBuffer out = new StringBuffer();
diff --git a/971CV/src/org/frc971/VisionTuner.java b/971CV/src/org/frc971/VisionTuner.java
index a6f08c2..4aba589 100644
--- a/971CV/src/org/frc971/VisionTuner.java
+++ b/971CV/src/org/frc971/VisionTuner.java
@@ -9,6 +9,7 @@
import java.util.logging.Logger;
import java.io.FileNotFoundException;
+import java.io.IOException;
import javax.swing.JPanel;
import javax.swing.JSlider;
@@ -54,6 +55,8 @@
private final JSlider hueMaxSlider = new JSlider();
private final JSlider satMinSlider = new JSlider();
private final JSlider valMinSlider = new JSlider();
+
+ private ResultSender sender;
private int totalFrames = -1; // don't count the first (warmup) frame
private double totalMsec;
@@ -77,6 +80,13 @@
System.err.println("Warning: Logging initialization failed.");
}
+ //initialize result sender
+ try {
+ sender = new ResultSender();
+ }
+ catch (IOException e) {
+ LOG.severe("Server initialization failed: " + e.getMessage() + " Result reporting disabled.");
+ }
cameraFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
recognizer.showIntermediateStages(true);
@@ -155,6 +165,9 @@
LOG.fine("The recognizer took " + milliseconds + " ms, " +
(1000 * totalFrames / totalMsec) + " fps, %.2f avg");
}
+
+ //send results to atom. (and any connected clients)
+
}
private void previousImage() {
@@ -202,13 +215,18 @@
LOG.severe("Cannot find test images.");
}
else {
- HTTPClient client = new HTTPClient();
- for (;;) {
- ImageWithTimestamp to_process = client.GetFrame();
- if (to_process.image != null) {
- tuner.processImage(to_process.image);
- LOG.fine("Captured time: " + Double.toString(to_process.timestamp));
- }
+ try {
+ HTTPClient client = new HTTPClient();
+ for (;;) {
+ ImageWithTimestamp to_process = client.GetFrame();
+ if (to_process.image != null) {
+ tuner.processImage(to_process.image);
+ LOG.fine("Captured time: " + Double.toString(to_process.timestamp));
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.severe("Client initialization failed.");
}
}
}
diff --git a/971CV/src/org/frc971/private_aos_camera_jar.jar b/971CV/src/org/frc971/private_aos_camera_jar.jar
index a1b8467..c202fe8 100644
--- a/971CV/src/org/frc971/private_aos_camera_jar.jar
+++ b/971CV/src/org/frc971/private_aos_camera_jar.jar
Binary files differ