package oculusPrime;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Set;
import java.util.Vector;
import developer.Ros.navsystemstate;
public class State {
public enum values{
// motors
motionenabled, moving, movingforward, motorport, cameratilt, motorspeed,
// dock
dockgrabbusy, docking, dockstatus, autodocking, dockfound, dockmetrics,
// lights
floodlightlevel, spotlightbrightness, strobeflashon, fwdfloodlevel,
// users
driver, logintime, pendinguserconnected, telnetusers,
// audio video
videosoundmode, stream, driverstream, volume,
framegrabbusy, controlsinverted, lightlevel,
streamactivitythreshold, streamactivity,
motiondetect, objectdetect, streamactivityenabled, jpgstream,
record, sounddetect,
// not typically used by scripts, undocumented:
writingframegrabs,
// power
wallpower, batterylife, powerport, batteryinfo, batteryvolts,
powererror, forceundock,
// not typically used by scripts, undocumented:
redockifweakconnection, // undocumented
// system
javastartup, linuxboot, httpport, lastusercommand, cpu, guinotify, waitingforcpu, osarch,
// network
localaddress, externaladdress, ssid,
networksinrange, networksknown, gatewayaddress, relayserver, relayclient,
// odometry
distanceangle, direction, odometry, distanceanglettl, stopbetweenmoves, odometrybroadcast,
odomturndpms, odomturnpwm, odomupdated, odomlinearmpms, odomlinearpwm,
// not typically used by scripts, undocumented:
calibratingrotation,
// navigation
rosmapinfo, rosamcl, rosglobalpath, rosscan,
roscurrentgoal, rosmapupdated, rosmapwaypoints, navsystemstatus,
rossetgoal, rosgoalstatus, rosgoalcancel, navigationroute, rosinitialpose,
navigationrouteid, nextroutetime, roswaypoint,
rosarcmove, // to be documented
}
/** not to be broadcast over telnet channel when updated, to reduce chatter */
public enum nonTelnetBroadcast { batterylife, sysvolts, batteryinfo, rosscan, rosmapwaypoints, rosglobalpath,
odomturnpwm, odomlinearpwm, framegrabbusy, lastusercommand, cpu, odomupdated, lastodomreceived,
redockifweakconnection, networksinrange,
}
/** @return true if given command is in the sub-set */
public static boolean isNonTelnetBroadCast(final String str) {
try { nonTelnetBroadcast.valueOf(str); } catch (Exception e) {return false;}
return true;
}
public static final int ERROR = -1;
/** notify these on change events */
public Vector<Observer> observers = new Vector<Observer>();
/** reference to this singleton class */
private static State singleton = new State();
/** properties object to hold configuration */
private HashMap<String, String> props = new HashMap<String, String>();
public static State getReference() {
return singleton;
}
private State() {
props.put(values.javastartup.name(), String.valueOf(System.currentTimeMillis()));
props.put(values.telnetusers.name(), "0");
getLinuxUptime();
}
public void addObserver(Observer obs){
observers.add(obs);
}
@SuppressWarnings("unchecked")
public HashMap<String, String> getState(){
return (HashMap<String, String>) props.clone();
}
/** test for string equality. any nulls will return false */
private boolean equals(final String a, final String b){
String aa = get(a);
if(aa==null) return false;
if(b==null) return false;
if(aa.equals("")) return false;
if(b.equals("")) return false;
return aa.equalsIgnoreCase(b);
}
public boolean equals(State.values value, String b) {
return equals(value.name(), b);
}
@Override
public String toString(){
String str = "";
final Set<String> keys = props.keySet();
for(final Iterator<String> i = keys.iterator(); i.hasNext(); ){
final String key = i.next();
str += (key + " " + props.get(key) + "<br>");
}
return str;
}
public boolean equals(values a, navsystemstate b) {
return equals(a.name(), b.name());
}
/**
* block until timeout or until member == target
*
* @param member state key
* @param target block until timeout or until member == target
* @param timeout is the ms to wait before giving up
* @return true if the member was set to the target in less than the given timeout
*/
public boolean block(final values member, final String target, int timeout){
long start = System.currentTimeMillis();
String current = null;
while(true){
current = get(member);
if(current!=null){
if(target.equals(current)) return true;
if(target.startsWith(current)) return true;
}
Util.delay(1); // no higher, used by motion, odometry
if (System.currentTimeMillis()-start > timeout){
Util.debug("block() timeout: " + member.name(), this);
return false;
}
}
}
/** Put a name/value pair into the configuration */
synchronized void set(final String key, final String value) {
if(key==null) {
Util.log("set() null key!", this);
return;
}
if(value==null) {
Util.log("set() use delete() instead", this);
Util.log("set() null valu for key: " + key, this);
return;
}
try {
props.put(key.trim(), value.trim());
} catch (Exception e) {
Util.printError(e);
}
for(int i = 0 ; i < observers.size() ; i++) observers.get(i).updated(key.trim());
}
synchronized String get(final String key) {
String ans = null;
try {
ans = props.get(key.trim());
} catch (Exception e) {
System.err.println(e.getStackTrace());
return null;
}
return ans;
}
public void set(final String key, final long value) {
set(key, Long.toString(value));
}
public String get(values key){
return get(key.name());
}
/** true returns true, anything else returns false */
public boolean getBoolean(String key) {
boolean value = false;
try {
value = Boolean.parseBoolean(get(key));
} catch (Exception e) {
return false;
}
return value;
}
public int getInteger(final String key) {
String ans = null;
int value = ERROR;
try {
ans = get(key);
value = Integer.parseInt(ans);
} catch (Exception e) {
return ERROR;
}
return value;
}
public long getLong(final String key) {
String ans = null;
long value = ERROR;
try {
ans = get(key);
value = Long.parseLong(ans);
} catch (Exception e) {
return ERROR;
}
return value;
}
/** @return the ms since last app start */
public long getUpTime(){
return System.currentTimeMillis() - getLong(values.javastartup);
}
/** @return the ms since last user log in */
public long getLoginSince(){
return System.currentTimeMillis() - getLong(values.logintime);
}
public synchronized void set(String key, boolean b) {
if(b) set(key, "true");
else set(key, "false");
}
public synchronized boolean exists(values key) {
return props.containsKey(key.toString().trim());
}
public synchronized boolean exists(String key) {
return props.containsKey(key.trim());
}
synchronized void delete(String key) {
if(!exists(key)) return;
if(props.containsKey(key)) props.remove(key);
for(int i = 0 ; i < observers.size() ; i++) observers.get(i).updated(key);
Util.debug("delete: " + key, this);
}
public void delete(values key) {
if(exists(key)) delete(key.name());
}
public void set(values key, values value) {
set(key.name(), value.name());
}
public int getInteger(values key) {
return getInteger(key.name());
}
public long getLong(values key){
return getLong(key.name());
}
public boolean getBoolean(values key){
return getBoolean(key.name());
}
public void set(values key, long data){
set(key.name(), data);
}
public void set(values key, String value){
set(key.name(), value);
}
public void set(values key, boolean value){
set(key.name(), value);
}
public void set(values key, double d) {
set(key.name(), String.valueOf(d));
}
public void delete(PlayerCommands cmd) {
delete(cmd.name());
}
public double getDouble(String key) {
double value = ERROR;
if(get(key) == null) return value;
try {
value = Double.valueOf(get(key));
} catch (NumberFormatException e) {
Util.log("getDouble(): " + e.getMessage(), this);
}
return value;
}
public double getDouble(values key) {
return getDouble(key.name());
}
private void getLinuxUptime(){
new Thread(new Runnable() {
@Override
public void run() {
try {
Process proc = Runtime.getRuntime().exec(new String[]{"uptime", "-s"});
BufferedReader procReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = procReader.readLine();
Date date = new SimpleDateFormat("yyyy-MM-dd h:m:s", Locale.ENGLISH).parse(line);
set(values.linuxboot, date.getTime());
} catch (Exception e) {
Util.debug("getLinuxUptime(): "+ e.getLocalizedMessage());
}
}
}).start();
}
/*
public String dumpFile(){
return dumpFile(" no message ");
}
public String dumpFile(final String msg) {
if (!Settings.getReference().getBoolean(ManualSettings.debugenabled)) return null;
File dump = new File(Settings.logfolder + Util.sep + "state_" + System.currentTimeMillis() + ".log");
Util.log("State.dumpFile() file created: "+dump.getAbsolutePath(), this);
try {
FileWriter fw = new FileWriter(dump);
fw.append("# "+ new Date().toString() + " " + msg +"\r\n");
final Set<String> keys = props.keySet();
for(final Iterator<String> i = keys.iterator(); i.hasNext(); ){
final String key = i.next();
fw.append(key + " " + props.get(key) + "\r\n");
}
fw.append("# state history \r\n");
Vector<String> snap = Util.history;
for(int i = 0; i < snap.size() ; i++) fw.append(snap.get(i)+"\r\n");
fw.close();
} catch (Exception e) { Util.printError(e); }
return dump.getAbsolutePath();
}*/
}