Add ball detector indicator webserver.

Change-Id: Iddc5d76b909cadccbc27221af58758708199e5c5
diff --git a/y2016/dashboard/dashboard.h b/y2016/dashboard/dashboard.h
new file mode 100644
index 0000000..003820c
--- /dev/null
+++ b/y2016/dashboard/dashboard.h
@@ -0,0 +1,96 @@
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <atomic>
+#include <vector>
+
+#include "seasocks/PageHandler.h"
+#include "seasocks/PrintfLogger.h"
+#include "seasocks/StringUtil.h"
+#include "seasocks/WebSocket.h"
+
+#include "aos/linux_code/init.h"
+#include "aos/common/time.h"
+#include "aos/common/util/phased_loop.h"
+#include "aos/common/mutex.h"
+
+namespace y2016 {
+namespace dashboard {
+
+// Dashboard is a webserver that opens a socket and stream data from the robot
+// to the client. It is divided between the DataCollector, which polls
+// RunIteration to determine what to send to the client, and an instance of a
+// Seasocks server, which initiates a webserver on a port and opens a socket
+// for streaming data.
+
+// It is an adaption of http_status, which was a 2015 project
+// that plotted live position data from the robot queues on a webpage for
+// debugging.
+
+class DataCollector {
+ public:
+  DataCollector();
+  void RunIteration();
+
+  // Store a datapoint. In this case, we are reading data points to determine
+  // what color to display on the webpage indicators. Traditionally, this would
+  // be used to plot live data on a graph on the page.
+  void AddPoint(const ::std::string &name, double value);
+
+  // Method called by the websocket to get a JSON-packaged string containing,
+  // at most, a constant number of samples, starting at from_sample.
+  ::std::string Fetch(int32_t from_sample);
+
+  void operator()();
+  void Quit() { run_ = false; }
+
+ private:
+  // Returns a wrapped index based on the overflow size.
+  size_t GetIndex(size_t sample_id);
+
+  struct ItemDatapoint {
+    double value;
+    ::aos::time::Time time;
+  };
+
+  struct SampleItem {
+    ::std::string name;
+    ::std::vector<ItemDatapoint> datapoints;
+  };
+
+  // Storage vector that is written and overwritten with data in a FIFO fashion.
+  ::std::vector<SampleItem> sample_items_;
+
+  ::std::string cur_raw_data_;
+  int32_t sample_id_;          // Last sample id used.
+  size_t measure_index_;      // Last measure index used.
+  const int32_t overflow_id_;  // Vector wrapping size.
+
+  ::std::atomic<bool> run_{true};
+  ::aos::Mutex mutex_;
+};
+
+class SocketHandler : public seasocks::WebSocket::Handler {
+ public:
+  SocketHandler();
+  void onConnect(seasocks::WebSocket* connection) override;
+  void onData(seasocks::WebSocket* connection, const char* data) override;
+  void onDisconnect(seasocks::WebSocket* connection) override;
+  void Quit();
+
+ private:
+  ::std::set<seasocks::WebSocket*> connections_;
+  DataCollector data_collector_;
+  ::std::thread data_collector_thread_;
+};
+
+class SeasocksLogger : public seasocks::PrintfLogger {
+ public:
+  SeasocksLogger(Level min_level_to_log);
+  void log(Level level, const char* message) override;
+};
+
+}  // namespace dashboard
+}  // namespace y2016