package oculusPrime; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.Vector; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import developer.Navigation; import developer.NavigationUtilities; import oculusPrime.State.values; import oculusPrime.commport.PowerLogger; public class DashboardServlet extends HttpServlet implements Observer { static final long serialVersionUID = 1L; // private static final int MAX_STATE_HISTORY = 40; private static final String HTTP_REFRESH_DELAY_SECONDS = "30"; static final String runroute = "<a href=\"dashboard?action=runroute\">"; static final String viewslinks = "<a href=\"navigationlog/index.html\" target=\"_blank\">navigation log</a>\n"+ "<a href=\"/oculusPrime/media\" target=\"_blank\">media files</a>" + "<a href=\"dashboard?view=routes\">route stats</a>\n" + // "<a href=\"dashboard?view=drive\">drive</a>\n" + "<a href=\"dashboard?action=snapshot\" target=\"_blank\">snaphot</a>\n"+ "<a href=\"dashboard?view=users\">users</a>\n" + "<a href=\"dashboard?view=stdout\">stdout</a>\n" + "<a href=\"dashboard?view=history\">history</a>\n" + "<a href=\"dashboard?view=state\">state</a>\n"; static final String commandlinks = "<a href=\"dashboard?action=gotodock\">return dock</a>\n" + "<a href=\"dashboard?action=cancel\">cancel route</a>\n" + "<a href=\"dashboard?action=deletelogs\">delete log files</a>\n" + "<a href=\"dashboard?action=trunc\">truncate media</a>" + "<a href=\"dashboard?action=archivelogs\">archive log folder</a>" + "<a href=\"dashboard?action=reboot\">reboot linux</a>" + "<a href=\"dashboard?action=restart\">restart java</a>" + "<a href=\"dashboard?action=email\">send email</a>\n"; static final double VERSION = new Updater().getCurrentVersion(); // static Vector<String> history = new Vector<String>(); static Settings settings = Settings.getReference(); static BanList ban = BanList.getRefrence(); static State state = State.getReference(); static Application app = null; static String httpport = null; static Vector<String> pointslist; String delay = "30"; String estimatedmeters; String estimatedseconds; long time; final String css = getCSS(); final int restarts = settings.getInteger(ManualSettings.restarted); public String getCSS(){ StringBuffer buffer = new StringBuffer(); try { String line = null; FileInputStream filein = new FileInputStream(System.getenv("RED5_HOME") + "/webapps/oculusPrime/dashboard.css"); BufferedReader reader = new BufferedReader(new InputStreamReader(filein)); while ((line = reader.readLine()) != null) buffer.append(line + "\n"); reader.close(); filein.close(); } catch (Exception e) { Util.log("getCSS(): " + e.getMessage(), this); } return buffer.toString(); } public void init(ServletConfig config) throws ServletException { super.init(config); state = State.getReference(); httpport = state.get(State.values.httpport); settings = Settings.getReference(); ban = BanList.getRefrence(); state.addObserver(this); } public static void setApp(Application a){app = a;} public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if( ! settings.getBoolean(ManualSettings.developer.name())){ Util.log("dangerous.. not in developer mode: "+request.getRemoteAddr(), this); response.sendRedirect("/oculusPrime"); return; } if( ! ban.knownAddress(request.getRemoteAddr())){ Util.log("unknown address: sending to login: "+request.getRemoteAddr(), this); response.sendRedirect("/oculusPrime"); return; } String view = null; String action = null; String route = null; String move = null; try { view = request.getParameter("view"); delay = request.getParameter("delay"); action = request.getParameter("action"); route = request.getParameter("route"); move = request.getParameter("move"); } catch (Exception e) {} if(delay == null) delay = HTTP_REFRESH_DELAY_SECONDS; if(move != null){ if(state.equals(values.dockstatus, AutoDock.DOCKED)){ state.set(values.motionenabled, true); double distance = 1.0; app.driverCallServer(PlayerCommands.forward, String.valueOf(distance)); Util.delay((long) (distance / state.getDouble(values.odomlinearmpms.name())) + 2000); } else app.driverCallServer(PlayerCommands.nudge, move); } if(action != null && app != null){ if(action.equalsIgnoreCase("camon")){ new Thread(new Runnable() { public void run(){ app.driverCallServer(PlayerCommands.publish, "camera"); Util.delay(4000); // TODO: BETTER WAY TO KNOW IF CAMERA IS ON? if(Navigation.turnLightOnIfDark()) Util.log("light was turned on because was dark", this); }}).start(); } if(action.equalsIgnoreCase("camoff")) { app.driverCallServer(PlayerCommands.publish, "stop"); app.driverCallServer(PlayerCommands.spotlight, "0"); } if( route != null ){ // Util.debug("......doGet(): route: " + route, this); // if(action.equalsIgnoreCase("resetstats")) app.driverCallServer(PlayerCommands.resetroutedata, route); if(action.equalsIgnoreCase("gotowp")) app.driverCallServer(PlayerCommands.gotowaypoint, route); if(action.equalsIgnoreCase("runroute")) app.driverCallServer(PlayerCommands.runroute, route); } if(action.equalsIgnoreCase("cancel")) { // Util.debug("......doGet(): cancel route: " + state.get(values.navigationroute), this); app.driverCallServer(PlayerCommands.move, "stop"); app.driverCallServer(PlayerCommands.cancelroute, null); Util.delay(3000); app.driverCallServer(PlayerCommands.gotodock, null); } if(action.equalsIgnoreCase("debugon")) app.driverCallServer(PlayerCommands.writesetting, ManualSettings.debugenabled.name() + " true"); if(action.equalsIgnoreCase("debugoff")) app.driverCallServer(PlayerCommands.writesetting, ManualSettings.debugenabled.name() + " false"); if(action.equalsIgnoreCase("startrec")) app.driverCallServer(PlayerCommands.record, "true dashboard"); if(action.equalsIgnoreCase("stoprec")) app.driverCallServer(PlayerCommands.record, "false"); if(action.equalsIgnoreCase("motor")) app.driverCallServer(PlayerCommands.motorsreset, null); if(action.equalsIgnoreCase("power")) app.driverCallServer(PlayerCommands.powerreset, null); if(action.equalsIgnoreCase("gotodock")) app.driverCallServer(PlayerCommands.gotodock, null); if(action.equalsIgnoreCase("startnav")) app.driverCallServer(PlayerCommands.startnav, null); if(action.equalsIgnoreCase("stopnav")) app.driverCallServer(PlayerCommands.stopnav, null); if(action.equalsIgnoreCase("redock")) app.driverCallServer(PlayerCommands.redock, null); if(action.equalsIgnoreCase("deletelogs")) app.driverCallServer(PlayerCommands.deletelogs, null); if(action.equalsIgnoreCase("archivelogs")) app.driverCallServer(PlayerCommands.archivelogs, null); if(action.equalsIgnoreCase("trunclogs")){ Util.log(".... trunc logs stub ....",this); // Util.truncStaleNavigationFiles(); Util.truncStaleAudioVideo(); Util.truncStaleFrames(); } if(action.equalsIgnoreCase("gui")) state.delete(values.guinotify); if(action.equalsIgnoreCase("email")) sendEmail(); if(action.equalsIgnoreCase("reboot")){ new Thread(new Runnable() { public void run(){ Util.log("reboot called, going down..", this); Util.delay(2000); // redirect before calling.. app.driverCallServer(PlayerCommands.reboot, null); }}).start(); } if(action.equalsIgnoreCase("restart")){ new Thread(new Runnable(){ public void run(){ // app.driverCallServer(PlayerCommands.move, "stop"); Util.log("restart called, going down..", this); Util.delay(2000); // redirect before calling.. app.driverCallServer(PlayerCommands.restart, null); }}).start(); } if(action.equalsIgnoreCase("snapshot")) { sendSnap(request, response); return; } /* if(action.equalsIgnoreCase("save")) { new Thread(new Runnable() { public void run() { if( ! new Downloader().FileDownload("http://" + state.get(values.localaddress) + ":" + httpport + "/oculusPrime/dashboard?action=snapshot", "snapshot_"+ System.currentTimeMillis() +".txt", "log")) Util.log("snapshot save failed", this); }}).start(); } */ response.sendRedirect("/oculusPrime/dashboard?delay=" + delay); } response.setContentType("text/html"); PrintWriter out = response.getWriter(); if(view != null){ if(view.equalsIgnoreCase("drive")){ out.println("<html><head><meta http-equiv=\"refresh\" content=\""+ delay + "\"></head><body> \n"); out.println("<br/>  <a href=\"dashboard\">dashboard</a>    "); out.println("nudge: <a href=\"dashboard?view=drive&move=forward\">forward</a>  "); out.println("<a href=\"dashboard?view=drive&move=backward\">backward</a>  "); out.println("<a href=\"dashboard?view=drive&move=left\">left</a>  "); out.println("<a href=\"dashboard?view=drive&move=right\">right</a>    "); out.println("<br/><img src=\"frameGrabHTTP\"><br/>\n"); out.println("\n</body></html> \n"); out.close(); } if(view.equalsIgnoreCase("users")){ out.println("<html><head><meta http-equiv=\"refresh\" content=\""+ delay + "\"></head><body> \n"); out.println("<a href=\"dashboard\">dashboard</a>  <br/>\n"); out.println(ban + "<br />\n"); out.println(ban.tail(30) + "\n"); String str = "RTMP users login records:<br>"; for (int i = 0; i < LoginRecords.list.size(); i++) str += i + " " + LoginRecords.list.get(i).toString() + "<br>"; out.println("<br>" + str); out.println("\n</body></html> \n"); out.close(); } if(view.equalsIgnoreCase("state")){ out.println("<html><body> \n"); out.println("    <a href=\"dashboard\">dashboard</a>"); out.println("    <a href=\"dashboard?view=history\">history</a><br /><br />\n"); out.println(toHTML() + "\n"); out.println("\n</body></html> \n"); out.close(); } if(view.equalsIgnoreCase("routes")){ out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"); out.println("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\"><title>Oculus Prime Route Statistics</title> \n"); out.println("<style type=\"text/css\">"); out.println("body, p, ol, ul {font-family: verdana, arial, helvetica, sans-serif; font-size: 16px;}"); out.println("th, td { text-align: left; padding: 12px; }"); out.println("tr:nth-child(even){background-color: #f2f2f2}"); out.println("th { background-color: #4CAF50; color: white; }"); out.println("</style><html><body>\n"); out.println("\n"); // out.println("    <a href=\"dashboard\">back to dashboard</a></br></br>"); out.println(NavigationUtilities.getRouteStatsHTML() + "\n"); out.println("\n</body></html> \n"); out.close(); } if(view.equalsIgnoreCase("stdout")){ out.println("<html><head><meta http-equiv=\"refresh\" content=\""+ delay + "\"></head><body> \n"); out.println("<a href=\"dashboard\">dashboard</a>   \n" + new File(Settings.stdout).getAbsolutePath() + "<br /><br />\n"); out.println(Util.tail(35) + "\n"); out.println("\n</body></html> \n"); out.close(); } if(view.equalsIgnoreCase("power")){ out.println("<html><head><meta http-equiv=\"refresh\" content=\""+ delay + "\"></head><body> \n"); out.println("<a href=\"dashboard\">dashboard</a>   \n" + new File(PowerLogger.powerlog).getAbsolutePath() + "<br /><br />\n"); out.println(PowerLogger.tail(45) + "\n"); out.println("\n</body></html> \n"); out.close(); } /* if(view.equalsIgnoreCase("history")){ out.println("<html><head><meta http-equiv=\"refresh\" content=\""+ delay + "\"></head><body> \n"); out.println("<a href=\"dashboard\">dashboard</a>"); out.println("    <a href=\"dashboard?view=state\">state</a><br /><br />\n"); out.println(getHistory().replaceAll("\n", "<br>\n")); out.println("\n</body></html> \n"); out.close(); } */ } // default view out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"); out.println("<html>\n<head><meta http-equiv=\"refresh\" content=\""+ delay + "\">\n<title>Oculus Prime</title>\n<style type=\"text/css\">"+ css +"</style></head>\n<body> \n"); out.println(toDashboard(request.getServerName()+":"+request.getServerPort() + "/oculusPrime/dashboard") + "\n"); out.println("\n</body></html>\n"); out.close(); } public void sendEmail(){ new Thread(new Runnable() { public void run() { StringBuffer text = new StringBuffer(); text.append("\n\r-- " + new Date() + " --\n"); text.append(Util.tail(999).replaceAll("<br>", "\n")); // text.append("\n\r -- state history --\n"); // text.append(getHistory() + "\n\r"); text.append("\n\r -- state values -- \n"); text.append(state.toString().replaceAll("<br>", "\n")); text.append("\n\r -- battery --\n"); text.append(PowerLogger.tail(45) + "\n"); text.append("\n\r -- settings --\n"); text.append(Settings.getReference().toString().replaceAll("<br>", "\n")); new SendMail("oculus prime snapshot", text.toString()); // Util.delay(5000); // new SendMail("oculus prime log files", "see attached", new String[]{ Settings.settingsfile, Navigation.navroutesfile.getAbsolutePath() }); }}).start(); } public String toHTML(){ StringBuffer str = new StringBuffer("<table>"); HashMap<String, String> props = state.getState(); Set<String> keys = props.keySet(); for(Iterator<String> i = keys.iterator(); i.hasNext();){ try { if( !i.hasNext()) break; String key = i.next(); if(key.equals(values.rosamcl.name())) key = i.next(); if(key.equals(values.rosglobalpath.name())) key = i.next(); if(key.equals(values.rosmapinfo.name())) key = i.next(); if(key.equals(values.rosscan.name())) key = i.next(); if(key.equals(values.rosmapwaypoints.name())) key = i.next(); if(key.equals(values.batteryinfo.name())) key = i.next(); if(key.equals(values.networksinrange.name())) key = i.next(); if(key.equals(values.rosmapinfo.name())) key = i.next(); str.append("<tr><td>" + key + "<td>" + props.get(key) + "</a>"); if( !i.hasNext()) break; key = i.next(); if(key.equals(values.rosamcl.name())) key = i.next(); if(key.equals(values.rosglobalpath.name())) key = i.next(); if(key.equals(values.rosmapinfo.name())) key = i.next(); if(key.equals(values.rosscan.name())) key = i.next(); if(key.equals(values.rosmapwaypoints.name())) key = i.next(); if(key.equals(values.batteryinfo.name())) key = i.next(); if(key.equals(values.networksinrange.name())) key = i.next(); if(key.equals(values.rosmapinfo.name())) key = i.next(); str.append("<td>" + key + "<td>" + props.get(key) + "</a>"); if( !i.hasNext()) break; } catch (Exception e) { break; } } Vector<String> points = getAllWaypoints(); String pnames = "NONE"; if(points.size() > 0) pnames = points.toString(); str.append("<tr><td colspan=\"9\"><hr><tr><td colspan=\"9\">wapoints: " + pnames); str.append("<tr><td colspan=\"9\"><hr><tr><td colspan=\"9\">null's"); for (values key : values.values()) if(! props.containsKey(key.name())) str.append(" " + key.name() + " "); str.append("</table>\n"); return str.toString(); } public void sendSnap(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text"); PrintWriter out = response.getWriter(); out.println("\n\r-- " + new Date() + " --\n\r"); out.println(Util.tail(999).replaceAll("<br>", "\n")); // out.println("\n\r -- state history --\n\r"); // out.println(getHistory() + "\n\r"); out.println("\n\r -- state values -- \n\r"); out.println(state.toString().replaceAll("<br>", "\n")); out.println("\n\r -- settings --\n\r"); out.println(Settings.getReference().toString().replaceAll("<br>", "\n")); out.println("\n\r -- route stats -- \n\r"); out.println(NavigationUtilities.getRouteStats() + "\n"); out.println("\n\r -- batter info -- \n\r"); out.println(PowerLogger.tail(99).replaceAll("<br>", "\n") + "\n"); out.close(); } public String toDashboard(final String url){ String motor, power; if(state.exists(values.powerport)) power = "<a href=\"dashboard?action=power\" >"+state.get(values.powerport)+"</a>"; else power = "<a href=\"dashboard?action=power\" >connect power</a>"; if(state.exists(values.motorport)) motor = "<a href=\"dashboard?action=motor\" >"+state.get(values.motorport)+"</a>"; else motor = "<a href=\"dashboard?action=motor\" >connect motors</a>"; String rec = state.get(values.record); if(rec == null) rec = "<td class='menu'>record<td class='off'><a href=\"dashboard?action=startrec\">  on</a>  |  <a href=\"dashboard?action=stoprec\">off</a>"; else { if(rec.contains("cam")){ rec = "<td class='menu'>record<td class='on'><a href=\"dashboard?action=startrec\">  on</a>  |  <a href=\"dashboard?action=stoprec\">off</a>"; } else { rec = "<td class='menu'>record<td class='off'><a href=\"dashboard?action=startrec\">  on</a>  |  <a href=\"dashboard?action=stoprec\">off</a>"; } } String cam = state.get(values.stream); if(cam == null) cam = ""; else { if(cam.contains("cam")) { cam = "<td class='menu'>camera<td class='on'><a href=\"dashboard?action=camon\">  on</a>  |  <a href=\"dashboard?action=camoff\">off</a>"; } else { cam = "<td class='menu'>camera<td class='off'><a href=\"dashboard?action=camon\">  on</a>  |  <a href=\"dashboard?action=camoff\">off</a>"; } } String od = "<td class='menu'>nav<td class='off'><a href=\"dashboard?action=startnav\"\">  on  </a>|  off"; if(state.getBoolean(values.odometry)) od = "<td class='menu'>nav<td class='on'>  on  |  <a href=\"dashboard?action=stopnav\">off</a>"; String debug = "<td class='menu'>debug<td class='off'><a href=\"dashboard?action=debugon\">  on  </a>|  off"; if(settings.getBoolean(ManualSettings.debugenabled)) debug = "<td class='menu'>debug<td class='on'>  on  |  <a href=\"dashboard?action=debugoff\">off</a>"; if(httpport == null) httpport = state.get(State.values.httpport); String dock = "undocked>"; if(state.equals(values.dockstatus, AutoDock.DOCKED)) dock = "<a href=\"dashboard?action=redock\" title=\"force re-dock the robot\">docked</a>"; if(!state.getBoolean(values.odometry) || state.equals(values.dockstatus, AutoDock.DOCKED)) dock = "<a href=\"dashboard?action=redock\" title=\"force re-dock the robot\">docked</a>"; if(state.equals(values.dockstatus, AutoDock.DOCKED)) dock = "<a href=\"dashboard?action=redock\" title=\"force re-dock the robot\">docked</a>"; if(state.equals(values.dockstatus, AutoDock.UNDOCKED)) dock = "<a href=\"dashboard?action=redock\">un-docked</a>"; if(state.equals(values.dockstatus, AutoDock.DOCKING)) dock = "docking"; if(state.equals(values.dockstatus, AutoDock.UNKNOWN)) dock = "UNKNOWN"; if(state.getBoolean(values.autodocking)) dock = "auto-docking"; //------------------- now build HTML buffer ------------------------------------------------------------// StringBuffer str = new StringBuffer("<table cellspacing=\"8\"><tbody>\n"); // version | views | ssid | rate str.append("\n<tr><td class='menu'>version " + VERSION); str.append("<td><div class=\"dropdown\"><button class=\"dropbtn\">commands</button><div class=\"dropdown-content\">\n" + commandlinks + "\n</div></div>"); str.append("\n<td class='menu'>ssid<td><a href=\"http://"+state.get(values.localaddress) +"\" target=\"_blank\">" + state.get(values.ssid)); if(delay.equals("5")) str.append("\n<td class='menu'>rate<td>" + "5 | <a href=\"dashboard?delay=10\">10</a> | <a href=\"dashboard?delay=30\">30</a>"); if(delay.equals("10")) str.append("\n<td class='menu'>rate<td>" + "<a href=\"dashboard?delay=5\">5</a> | 10 | <a href=\"dashboard?delay=30\">30</a>"); if(delay.equals("30")) str.append("\n<td class='menu'>rate<td>" + "<a href=\"dashboard?delay=5\">5</a> | <a href=\"dashboard?delay=10\">10</a> | 30"); // motor | wan | hdd str.append("\n<tr>"); str.append("<td class='menu'>motor<td>" + motor ); String ext = state.get(values.externaladdress); if( ext == null ) str.append("<td class='menu'>wan<td>disconnected"); else str.append("<td class='menu'>wan<td><a href=\"http://"+ ext + ":" + httpport + "/oculusPrime/" +"\" target=\"_blank\">" + ext + "</a>"); str.append( "<td class='menu'>hdd<td>" + Util.diskFullPercent() + "% used</a></tr> \n"); // power | lan | prime str.append("\n<tr>"); str.append("<td class='menu'>power<td>" + power ); str.append("<td class='menu'>lan<td><a href=\"http://"+state.get(values.localaddress) +"\" target=\"_blank\">" + state.get(values.localaddress) + "</a>"); str.append("<td class='menu'>prime<td>" + Util.countAllMbytes(".") + " mb</tr> \n"); // dock | battery | streams str.append("\n<tr>"); if( ! state.equals(values.dockstatus, AutoDock.DOCKED)) str.append("<td class='menu'>dock<td class='busy'>" + dock); else str.append("<td class='menu'>dock<td>" + dock); str.append("<td class='menu'>battery<td><a href=\"dashboard?view=power\">" + state.get(values.batterylife) + "</a>"); str.append("<td class='menu'>streams<td>" + Util.countAllMbytes(Settings.streamfolder) + "</a> mb</tr> \n" ); // record | booted | archive str.append("\n<tr>"); str.append(rec); str.append("<td class='menu'>booted<td>" + (((System.currentTimeMillis() - state.getLong(values.linuxboot)) / 1000) / 60)+ "</a> mins"); str.append("<td class='menu'>archive<td>"+ Util.countMbytes("./log/archive") + " mb</tr> \n" ); // camera | uptime | frames str.append("\n<tr>"); str.append(cam); if(restarts < 5) str.append("<td class='menu'>up time<td>" + (state.getUpTime()/1000)/60 + "</a> mins"); else str.append("<td class='menu'>up time<td class='busy'>" + (state.getUpTime()/1000)/60 + "</a> mins (" + restarts + ")"); str.append("<td class='menu'>frames<td>" + Util.countAllMbytes(Settings.framefolder) + " mb</tr> \n" ); // navigation | cpu | logs str.append("\n<tr>"); str.append(od); String cpuvalue; if(state.getBoolean(values.waitingforcpu)) cpuvalue = "<td class='busy'>" + state.get(values.cpu) + "%  waiting..</td>"; else cpuvalue = "<td>" + state.get(values.cpu) + "%"; str.append("<td class='menu'>cpu" + cpuvalue); str.append("<td class='menu'>logs<td>" + Util.countMbytes(Settings.logfolder) + " mb</tr> \n" ); // debug | telnet | ros str.append("\n<tr>"); str.append(debug + "<td class='menu'>telnet<td>" + state.get(values.telnetusers) + "<td class='menu'>ros<td>" + Util.getRosCheck() + "</tr> \n" ); // doesn't work on hidden file? Util.countMbytes(Settings.roslogfolder) str.append(getActiveRoute()); str.append("\n\n<tr><td class='menu'>routes<td>"+ getRouteLinks() +" \n"); String waypoint = state.get(values.roswaypoint); if(waypoint == null) waypoint = "not active"; String drop = "\n<td class='menu'>points<td><div class=\"dropdown\"><button class=\"dropbtn\">"+waypoint+"</button><div class=\"dropdown-content\">"; Vector<String> waypointsAll = getAllWaypoints(); if(waypointsAll != null){ for(int i = 0 ; i < waypointsAll.size() ; i++) { drop += "\n<a href=\"dashboard?action=gotowp&route="+ waypointsAll.get(i).replaceAll(" ", " ").trim() +"\">" + waypointsAll.get(i) + "</a> "; } } drop += "</div></div>"; str.append(drop); str.append("<td><div class=\"dropdown\"><button class=\"dropbtn\">views</button><div class=\"dropdown-content\">\n" + viewslinks + "\n</div></div>"); // str.append("<td><div class=\"dropdown\"><button class=\"dropbtn\">commands</button><div class=\"dropdown-content\">\n" + commandlinks + "\n</div></div>"); str.append("<td>"); // --- active --- // String m = "# " + Navigation.consecutiveroute + " "; if(pointslist != null) // m+= pointslist; for(int c = 0 ; c < pointslist.size(); c++ ) m+= "<a href=\"media?filter="+ pointslist.get(c) + "\" target=\"_blank\">" + pointslist.get(c) + "</a>, "; m += " <a href=\"dashboard?action=gotodock\">return to dock</a> "; // if(state.getBoolean(values.routeoverdue)) m += " *overdue* "; // if(state.getBoolean(values.waypointbusy)) m += " *waypointbusy* "; if(state.getBoolean(values.rosgoalcancel)) m += " *ros goal cancel* "; if(m.length() > 0) str.append("\n<tr><td class='menu'>active<td class='tail' colspan=\"11\">"+ m.trim() +"</tr>\n"); // --- gui notify --- // String msg = state.get(values.guinotify); if(msg == null) msg = ""; else msg += "  (<a href=\"dashboard?action=gui\">ignore</a>)"; if(msg.length() > 1) { msg = "<tr><td class='menu'>message<td class='tail' colspan=\"11\">" + msg + "</tr> \n"; str.append(msg); } str.append(getTail(12) + "\n"); str.append("\n</tbody></table>\n"); return str.toString(); } private String getRouteLinks(){ Vector<String> list = NavigationUtilities.getRoutes(); String rname = state.get(values.navigationroute); if(rname == null) rname = "not active"; String drop = "\n<div class=\"dropdown\"><button class=\"dropbtn\">"+rname+"</button><div class=\"dropdown-content\">"; for(int i = 0; i < list.size(); i++) drop += "<a href=\"dashboard?action=runroute&route="+list.get(i)+"\">" + list.get(i) + "</a>"; return drop += "</div></div>"; } private String getActiveRoute(){ String link = "<tr><td class='menu'>next<td>"; String rname = state.get(values.navigationroute); String next = "err"; rname = state.get(values.navigationroute); if(rname == null) rname = "xml: " + NavigationUtilities.getActiveRoute(); time = ((System.currentTimeMillis() - Navigation.routestarttime)/1000); next = state.get(values.roswaypoint); if(state.equals(values.dockstatus, AutoDock.DOCKED) && !state.getBoolean(values.odometry)){ if(state.exists(values.nextroutetime)){ next = ((state.getLong(values.nextroutetime) - System.currentTimeMillis())/1000)+ " sec"; time = 0; } } if(next==null) time = 0; link += next += "<td class='menu'>meters<td>" + Navigation.getRouteMeters() + " | " + estimatedmeters + "<td class='menu'>time<td>" + time + " | " + estimatedseconds; return link; } public static String tailFormated(int lines){ int i = 0; final long now = System.currentTimeMillis(); StringBuffer str = new StringBuffer(); if(Util.history.size() > lines) i = Util.history.size() - lines; for(; i < Util.history.size() ; i++){ String line = Util.history.get(i).substring(Util.history.get(i).indexOf(",")+1).trim(); String stamp = Util.history.get(i).substring(0, Util.history.get(i).indexOf(",")); line = line.replaceFirst("\\$[0-9]", ""); line = line.replaceFirst("^oculusprime.", ""); line = line.replaceFirst("^oculusPrime.", ""); line = line.replaceFirst("^Application.", ""); line = line.replaceFirst("^static, ", ""); double delta = (double)(now - Long.parseLong(stamp)) / (double) 1000; String unit = " sec "; String d = Util.formatFloat(delta, 0); if(delta > 60) { delta = delta / 60; unit = " min "; d = Util.formatFloat(delta, 1); } str.append("\n<tr><td class='menu'>" + d + " " + unit + "<td class='tail' colspan=\"11\">" + line.trim() + "</tr> \n"); } return str.toString(); } private String getTail(int lines){ String reply = "\n\n"; // <table cellspacing=\"8\"> \n"; reply += tailFormated(lines); // reply += ("\n</table>\n"); return reply; } /* private String getHistory(){ String reply = ""; for(int i = 0 ; i < history.size() ; i++) { long time = Long.parseLong(history.get(i).substring(0, history.get(i).indexOf(" "))); String mesg = history.get(i).substring(history.get(i).indexOf(" ")); String date = new Date(time).toString(); date = date.substring(10, date.length()-8).trim(); double delta = (double)(System.currentTimeMillis() - time) / (double) 1000; String unit = " sec "; if(delta > 60) { delta = delta / 60; unit = " min "; } reply += " " + Util.formatFloat(delta, 1) + " " + unit + "" + mesg.trim() + "\n"; } return reply; } */ @Override public void updated(String key){ // if(state.exists(key)) Util.log("updated: " + key + " " + state.get(key), this); // only read from file on change if(key.equals(values.navigationroute.name())){ if(state.exists(values.navigationroute)){ estimatedmeters = NavigationUtilities.getRouteDistanceEstimateString(state.get(values.navigationroute)); estimatedseconds = NavigationUtilities.getRouteTimeEstimateString(state.get(values.navigationroute)); pointslist = NavigationUtilities.getWaypointsForRoute(state.get(values.navigationroute)); } else { pointslist = null; estimatedmeters = "0"; estimatedseconds = "0"; time = 0; } } if(key.equals(values.dockstatus.name())){ if(state.equals(values.dockstatus, AutoDock.DOCKED)){ // estimatedmeters = "0"; // estimatedseconds = "0"; time = 0; } } // if(state.getBoolean(values.routeoverdue)) // state.set(values.guinotify, "route over due: " + NavigationUtilities.getActiveRoute()); // if(key.equals(values.framegrabbusy.name())) return; // if(key.equals(values.rosglobalpath.name())) return; // if(key.equals(values.rosscan.name())) return; if(key.equals(values.networksinrange.name())) return; if(key.equals(values.batteryinfo.name())) return; if(key.equals(values.batterylife.name())) return; if(key.equals(values.batteryvolts.name())) return; if(key.equals(values.cpu.name())) return; // trim size // if(history.size() > MAX_STATE_HISTORY) history.remove(0); // if(state.exists(key)) history.add(System.currentTimeMillis() + " " +key + " = " + state.get(key)); } public static Vector<String> getAllWaypoints(){ Vector<String> names = new Vector<String>(); if( ! state.exists(values.rosmapwaypoints)) return names; String[] points = state.get(values.rosmapwaypoints).split(","); for(int i = 0 ; i < points.length ; i++ ){ try { Double.parseDouble(points[i]); } catch (NumberFormatException e){ String value = points[i].replaceAll(" ", " ").trim(); // if(value.contains(" ")) Util.log("getAllWaypoints(): ..WARNING.. html chars point: " + value); // if(names.contains(value)) Util.log("getAllWaypoints(): ..WARNING.. duplicate point: " + value); if( ! names.contains(value)) names.add(points[i]); } } return names; } }