mirror of
https://github.com/TimeCrafters/UltimateGoal.git
synced 2025-12-15 14:02:33 +00:00
Updated to Ultimate Goal
This commit is contained in:
141
TeamCode/src/main/java/org/cyberarm/NeXT/DataStruct.java
Normal file
141
TeamCode/src/main/java/org/cyberarm/NeXT/DataStruct.java
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package org.cyberarm.NeXT;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class DataStruct {
|
||||||
|
public String name;
|
||||||
|
public boolean enabled;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Hash of Strings mapped to Strings, those strings are various types mapped to stings:
|
||||||
|
Boolean -> "Bxfalse"
|
||||||
|
Integer -> "Ix100"
|
||||||
|
Integer -> "Lx123456789"
|
||||||
|
Double -> "Dx0.1"
|
||||||
|
Float -> "Fx10.1"
|
||||||
|
String -> "SxWords can go here."
|
||||||
|
|
||||||
|
DataStruct.valueOf(Hash.get("distanceToDrive")) -> 100
|
||||||
|
*/
|
||||||
|
private HashMap<String, String> variables;
|
||||||
|
|
||||||
|
public DataStruct() {
|
||||||
|
this.variables = new HashMap<>();
|
||||||
|
}
|
||||||
|
public DataStruct(String name, boolean enabled, HashMap<String, String> variables) {
|
||||||
|
this.name = name;
|
||||||
|
this.enabled = enabled;
|
||||||
|
this.variables = variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean enabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, String> variables(String power) {
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T variable(String key) throws NullPointerException {
|
||||||
|
if (variables.get(key.trim()) == null) {
|
||||||
|
throw(new NullPointerException("Action \""+ name +"\" has no Variable called \""+ key.trim() +"\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return valueOf(variables.get(key.trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> T valueOf(String value) {
|
||||||
|
String[] split = value.split("x");
|
||||||
|
|
||||||
|
switch (split[0]) {
|
||||||
|
case "B": {
|
||||||
|
return (T) Boolean.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "D": {
|
||||||
|
return (T) Double.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "F": {
|
||||||
|
return (T) Float.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "I": {
|
||||||
|
return (T) Integer.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "L": {
|
||||||
|
return (T) Long.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "S": {
|
||||||
|
return (T) String.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String typeOf(String value) {
|
||||||
|
String[] split = value.split("x");
|
||||||
|
|
||||||
|
switch (split[0]) {
|
||||||
|
case "B": {
|
||||||
|
return "Boolean";
|
||||||
|
}
|
||||||
|
case "D": {
|
||||||
|
return "Double";
|
||||||
|
}
|
||||||
|
case "F": {
|
||||||
|
return "Float";
|
||||||
|
}
|
||||||
|
case "I": {
|
||||||
|
return "Integer";
|
||||||
|
}
|
||||||
|
case "L": {
|
||||||
|
return "Long";
|
||||||
|
}
|
||||||
|
case "S": {
|
||||||
|
return "String";
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return "=!UNKNOWN!=";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String encodeValue(String type, String value) {
|
||||||
|
switch (type) {
|
||||||
|
case "Boolean": {
|
||||||
|
return "Bx"+value;
|
||||||
|
}
|
||||||
|
case "Double": {
|
||||||
|
return "Dx"+value;
|
||||||
|
}
|
||||||
|
case "Float": {
|
||||||
|
return "Fx"+value;
|
||||||
|
}
|
||||||
|
case "Integer": {
|
||||||
|
return "Ix"+value;
|
||||||
|
}
|
||||||
|
case "Long": {
|
||||||
|
return "Lx"+value;
|
||||||
|
}
|
||||||
|
case "String": {
|
||||||
|
return "Sx"+value;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return "=!UNKNOWN!=";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package org.cyberarm.NeXT;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class StateConfiguration {
|
||||||
|
private boolean loadSuccessful = false;
|
||||||
|
private ArrayList<DataStruct> dataStructs;
|
||||||
|
private HashMap<String, DataStruct> actions;
|
||||||
|
|
||||||
|
public StateConfiguration() {
|
||||||
|
dataStructs = new ArrayList<>();
|
||||||
|
actions = new HashMap<>();
|
||||||
|
|
||||||
|
// Load configuration file.
|
||||||
|
if (loadJSON()) {
|
||||||
|
Log.i("TC_CONFIG", "Successfully loaded configuration file.");
|
||||||
|
|
||||||
|
for (DataStruct dataStruct : dataStructs) {
|
||||||
|
actions.put(dataStruct.name.trim(), dataStruct);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.e("TC_CONFIG", "FAILED TO LOAD CONFIGURATION FILE!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataStruct get(String key) throws NullPointerException {
|
||||||
|
if (actions.get(key.trim()) == null) {
|
||||||
|
throw(new NullPointerException("Config has no Action called \""+ key.trim() +"\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions.get(key.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allow(String key) throws NullPointerException {
|
||||||
|
if (get(key.trim()) == null) {
|
||||||
|
throw(new NullPointerException("Config has no Action called \""+ key.trim() +"\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return get(key.trim()).enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean loadJSON() {
|
||||||
|
boolean loadSuccessful = false;
|
||||||
|
|
||||||
|
File file = new File(getDirectory() + File.separator + "config.json");
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
|
||||||
|
if (file.exists()) {
|
||||||
|
try {
|
||||||
|
BufferedReader br = new BufferedReader(new FileReader(file));
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
text.append(line);
|
||||||
|
text.append('\n');
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
DataStruct[] array = gson.fromJson(text.toString(), DataStruct[].class);
|
||||||
|
this.dataStructs = new ArrayList<>(Arrays.asList(array));
|
||||||
|
|
||||||
|
loadSuccessful = true;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println(e);
|
||||||
|
// TODO: handle this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadSuccessful = loadSuccessful;
|
||||||
|
return loadSuccessful;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDirectory() {
|
||||||
|
return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "FIRST_TC_CONFIG";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasLoadSuccessful() { return loadSuccessful; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package org.cyberarm.container;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.qualcomm.robotcore.hardware.Gamepad;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class InputChecker {
|
||||||
|
private Gamepad gamepad;
|
||||||
|
private HashMap<String, Byte> buttons;
|
||||||
|
private ArrayList<String> buttonList;
|
||||||
|
private byte NULL = 0,
|
||||||
|
PRESSED = 1,
|
||||||
|
RELEASED= 2;
|
||||||
|
public InputChecker(Gamepad gamepad) {
|
||||||
|
this.gamepad = gamepad;
|
||||||
|
buttons = new HashMap<>();
|
||||||
|
buttonList = new ArrayList<>();
|
||||||
|
|
||||||
|
buttonList.add("a"); buttonList.add("b"); buttonList.add("x"); buttonList.add("y");
|
||||||
|
buttonList.add("start"); buttonList.add("guide"); buttonList.add("back");
|
||||||
|
buttonList.add("left_bumper"); buttonList.add("right_bumper");
|
||||||
|
buttonList.add("left_stick_button"); buttonList.add("right_stick_button");
|
||||||
|
buttonList.add("dpad_left"); buttonList.add("dpad_right");
|
||||||
|
buttonList.add("dpad_up"); buttonList.add("dpad_down");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
for (int i = 0; i < buttonList.size(); i++) {
|
||||||
|
try {
|
||||||
|
Field field = gamepad.getClass().getDeclaredField(buttonList.get(i));
|
||||||
|
|
||||||
|
if (field.getBoolean(gamepad)) {
|
||||||
|
buttons.put(buttonList.get(i), PRESSED);
|
||||||
|
} else {
|
||||||
|
if (buttons.get(buttonList.get(i)) != null && buttons.get(buttonList.get(i)) == PRESSED) {
|
||||||
|
buttons.put(buttonList.get(i), RELEASED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NoSuchFieldException|IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean check(String button) {
|
||||||
|
boolean state = false;
|
||||||
|
if (buttons.containsKey(button) && buttons.get(button) == RELEASED) {
|
||||||
|
Log.d("InputChecker","button \""+button+"\" has been released on \"gamepad"+gamepad.getGamepadId()+"\"");
|
||||||
|
state = true;
|
||||||
|
buttons.put(button, NULL);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
package org.cyberarm.engine.V2;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CyberarmEngine Version 2.0 | October 26th 2018
|
||||||
|
* AN Experimental reimplementation of GoldfishPi's original Engine system.
|
||||||
|
* Designed to be easily maintainable, extensible, and easy to understand.
|
||||||
|
*/
|
||||||
|
public abstract class CyberarmEngine extends OpMode {
|
||||||
|
|
||||||
|
public static CyberarmEngine instance;
|
||||||
|
//Array To Hold States
|
||||||
|
private ArrayList<CyberarmState> cyberarmStates = new ArrayList<>();
|
||||||
|
private int activeStateIndex = 0;
|
||||||
|
private boolean isRunning;
|
||||||
|
|
||||||
|
private static String TAG = "PROGRAM.ENGINE: ";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when INIT button on Driver Station is pushed
|
||||||
|
* ENSURE to call super.init() if you override this method
|
||||||
|
*/
|
||||||
|
public void init() {
|
||||||
|
CyberarmEngine.instance = this;
|
||||||
|
isRunning = false;
|
||||||
|
|
||||||
|
setup();
|
||||||
|
|
||||||
|
isRunning = true;
|
||||||
|
|
||||||
|
for (CyberarmState state: cyberarmStates) {
|
||||||
|
initState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup states for engine to use
|
||||||
|
* For example:
|
||||||
|
* <pre>
|
||||||
|
* @<code>
|
||||||
|
* public void setup() {
|
||||||
|
* addState(new TestState());
|
||||||
|
* addState(new AnotherState(100, 500));
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public abstract void setup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when START button on Driver Station is pushed
|
||||||
|
* ENSURE to call super.start() if you override this method
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
if (cyberarmStates.size() > 0) {
|
||||||
|
runState(cyberarmStates.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Engine main loop
|
||||||
|
* ENSURE to call super.loop() if you override this method
|
||||||
|
*/
|
||||||
|
public void loop() {
|
||||||
|
CyberarmState state;
|
||||||
|
|
||||||
|
// Try to set state to the current state, if it fails assume that there are no states to run
|
||||||
|
try {
|
||||||
|
state = cyberarmStates.get(activeStateIndex);
|
||||||
|
} catch(IndexOutOfBoundsException e) {
|
||||||
|
// The engine is now out of states.
|
||||||
|
stop();
|
||||||
|
|
||||||
|
telemetry.addLine("" + this.getClass().getSimpleName() + " is out of states to run!");
|
||||||
|
telemetry.addLine();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add telemetry to show currently running state
|
||||||
|
telemetry.addLine("Running state: " +state.getClass().getSimpleName() + ". State: " + activeStateIndex + " of " + (cyberarmStates.size()-1));
|
||||||
|
telemetry.addLine();
|
||||||
|
|
||||||
|
if (state.getHasFinished() && state.childrenHaveFinished()) {
|
||||||
|
activeStateIndex++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
state = cyberarmStates.get(activeStateIndex);
|
||||||
|
runState(state);
|
||||||
|
} catch(IndexOutOfBoundsException e) { /* loop will handle this in a few milliseconds */ }
|
||||||
|
|
||||||
|
} else {
|
||||||
|
stateTelemetry(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops every known state
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
for (CyberarmState state: cyberarmStates) {
|
||||||
|
stopState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively calls telemetry() on states
|
||||||
|
* @param state State to get telemetry
|
||||||
|
*/
|
||||||
|
private void stateTelemetry(CyberarmState state) {
|
||||||
|
if (!state.getHasFinished()) {
|
||||||
|
state.telemetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(CyberarmState childState : state.children) {
|
||||||
|
if (!childState.getHasFinished()) {
|
||||||
|
stateTelemetry(childState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when INIT button on Driver Station is pressed
|
||||||
|
* Recursively initiates states
|
||||||
|
* @param state State to initiate
|
||||||
|
*/
|
||||||
|
private void initState(CyberarmState state) {
|
||||||
|
state.init();
|
||||||
|
|
||||||
|
for(CyberarmState childState : state.children) {
|
||||||
|
initState(childState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when programs ends or STOP button on Driver Station is pressed
|
||||||
|
* Recursively stop states
|
||||||
|
* @param state State to stop
|
||||||
|
*/
|
||||||
|
private void stopState(CyberarmState state) {
|
||||||
|
state.setHasFinished(true);
|
||||||
|
state.stop();
|
||||||
|
|
||||||
|
for(CyberarmState childState : state.children) {
|
||||||
|
stopState(childState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively start up states
|
||||||
|
* @param state State to run
|
||||||
|
*/
|
||||||
|
protected void runState(CyberarmState state) {
|
||||||
|
final CyberarmState finalState = state;
|
||||||
|
// if (state.isRunning()) { return; } // Assume that we have already started running this state
|
||||||
|
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
finalState.start();
|
||||||
|
finalState.startTime = System.currentTimeMillis();
|
||||||
|
finalState.run();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
for (CyberarmState kid : state.children) {
|
||||||
|
runState(kid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add state to queue, will call init() on state if engine is running
|
||||||
|
* @param state State to add to queue
|
||||||
|
*/
|
||||||
|
public CyberarmState addState(CyberarmState state) {
|
||||||
|
Log.i(TAG, "Adding cyberarmState "+ state.getClass());
|
||||||
|
cyberarmStates.add(state);
|
||||||
|
|
||||||
|
if (isRunning()) { initState(state); }
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts state after the query state plus an offset to ensure logical insertion
|
||||||
|
* @param query State to add state after
|
||||||
|
* @param state State to be inserted
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CyberarmState insertState(CyberarmState query, CyberarmState state) {
|
||||||
|
int index = cyberarmStates.indexOf(query) + query.insertOffset;
|
||||||
|
cyberarmStates.add(index, state);
|
||||||
|
query.insertOffset++;
|
||||||
|
|
||||||
|
if (isRunning()) { initState(state); }
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will return false while Engine.setup() is executing, and be true after.
|
||||||
|
* @return Whether the engine main loop is running
|
||||||
|
*/
|
||||||
|
public boolean isRunning() {
|
||||||
|
return isRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return The index used to lookup the current state from cyberarmStates
|
||||||
|
*/
|
||||||
|
public int getActiveStateIndex() {
|
||||||
|
return activeStateIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
206
TeamCode/src/main/java/org/cyberarm/engine/V2/CyberarmState.java
Normal file
206
TeamCode/src/main/java/org/cyberarm/engine/V2/CyberarmState.java
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
package org.cyberarm.engine.V2;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A State for use with CyberarmEngineV2
|
||||||
|
*/
|
||||||
|
public abstract class CyberarmState implements Runnable {
|
||||||
|
|
||||||
|
private volatile boolean isRunning, hasFinished;
|
||||||
|
public static String TAG = "PROGRAM.STATE";
|
||||||
|
public CyberarmEngine engine = CyberarmEngine.instance;
|
||||||
|
public ArrayList<CyberarmState> children = new ArrayList<>();
|
||||||
|
public long startTime = 0;
|
||||||
|
public int insertOffset = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when INIT button on Driver Station is pushed
|
||||||
|
*/
|
||||||
|
public void init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when state has begin to run
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called while State is running
|
||||||
|
*/
|
||||||
|
public abstract void exec();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State's main loop, calls exec() until hasFinished is true
|
||||||
|
* DO NO OVERRIDE
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
isRunning = true;
|
||||||
|
while (!hasFinished) {
|
||||||
|
exec();
|
||||||
|
}
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place telemetry calls in here instead of inside exec() to have them displayed correctly on the Driver Station
|
||||||
|
* (States update thousands of times per second, resulting in missing or weirdly formatted telemetry if telemetry is added in exec())
|
||||||
|
*/
|
||||||
|
public void telemetry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when Engine is finished
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a state which runs in parallel with this one
|
||||||
|
*/
|
||||||
|
public CyberarmState addParallelState(CyberarmState state) {
|
||||||
|
Log.i(TAG, "Adding " + state.getClass() + " to " + this.getClass());
|
||||||
|
children.add(state);
|
||||||
|
|
||||||
|
if (isRunning()) { state.init(); engine.runState(state); }
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a state to engine which will run after this one finishes
|
||||||
|
*/
|
||||||
|
public CyberarmState addState(CyberarmState state) {
|
||||||
|
engine.insertState(this, state);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not state has children
|
||||||
|
* @return True if state has children, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasChildren() {
|
||||||
|
return (children.size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have all of the states children finished running themselves?
|
||||||
|
* @return Wether or not all children have finished running
|
||||||
|
*/
|
||||||
|
public boolean childrenHaveFinished() {
|
||||||
|
return childrenHaveFinished(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Have all of the states children finished running themselves?
|
||||||
|
* @param kids ArrayList of children to check for hasFinished()
|
||||||
|
* @return Whether or not all children have finished running
|
||||||
|
*/
|
||||||
|
public boolean childrenHaveFinished(ArrayList<CyberarmState> kids) {
|
||||||
|
boolean allDone = true;
|
||||||
|
|
||||||
|
for (CyberarmState state : kids) {
|
||||||
|
if (!state.hasFinished) {
|
||||||
|
allDone = false;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!state.childrenHaveFinished()) {
|
||||||
|
allDone = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return The number of milliseconds this state has been running for
|
||||||
|
*/
|
||||||
|
public double runTime() {
|
||||||
|
return (System.currentTimeMillis() - startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether state has finished or not
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public void setHasFinished(boolean value) {
|
||||||
|
hasFinished = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Get value of hasFinished
|
||||||
|
*/
|
||||||
|
public boolean getHasFinished() {
|
||||||
|
return hasFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Get value of isRunning
|
||||||
|
*/
|
||||||
|
public boolean isRunning() {
|
||||||
|
return isRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param timems How long to sleep in milliseconds
|
||||||
|
*/
|
||||||
|
public void sleep(long timems) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(timems);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param width How many characters wide to be
|
||||||
|
* @param percentCompleted Number between 0.0 and 100.0
|
||||||
|
* @param bar What character to draw the completion bar with
|
||||||
|
* @param padding What character to draw non-completed bar with
|
||||||
|
* @return A string
|
||||||
|
*/
|
||||||
|
public String progressBar(int width, double percentCompleted, String bar, String padding) {
|
||||||
|
String percentCompletedString = "" + Math.round(percentCompleted) + "%";
|
||||||
|
double activeWidth = (width - 2) - percentCompletedString.length();
|
||||||
|
|
||||||
|
String string = "[";
|
||||||
|
double completed = (percentCompleted / 100.0) * activeWidth;
|
||||||
|
|
||||||
|
for (int i = 0; i <= ((int) activeWidth); i++) {
|
||||||
|
if (i == ((int) activeWidth) / 2) {
|
||||||
|
string += percentCompletedString;
|
||||||
|
} else {
|
||||||
|
if (i <= (int) completed && (int) completed > 0) {
|
||||||
|
string += bar;
|
||||||
|
} else {
|
||||||
|
string += padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string += "]";
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param width How many characters wide to be
|
||||||
|
* @param percentCompleted Number between 0.0 and 100.0
|
||||||
|
* @return A string
|
||||||
|
*/
|
||||||
|
public String progressBar(int width, double percentCompleted) {
|
||||||
|
return progressBar(width, percentCompleted, "=", " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
28
TeamCode/src/main/java/org/cyberarm/engine/V2/README.txt
Normal file
28
TeamCode/src/main/java/org/cyberarm/engine/V2/README.txt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
CyberarmEngine V2 Architecture
|
||||||
|
|
||||||
|
Engine
|
||||||
|
-> [States]
|
||||||
|
-> [ParallelStates]
|
||||||
|
|
||||||
|
Start with an Engine and override setup():
|
||||||
|
|
||||||
|
public class Engine extends CyberarmEngineV2 {
|
||||||
|
public void setup() {
|
||||||
|
addState(new State(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NOTE: states do not need to be passed the instance of Engine as they have a field 'cyberarmEngine'
|
||||||
|
which is set to CyberarmEngineV2.instance when they are created.
|
||||||
|
|
||||||
|
States can have 'children' which are also States, which run in parallel with their parent. There is
|
||||||
|
no fixed limit to how many grandchildren can exist (Children themselves can have children.):
|
||||||
|
|
||||||
|
public class State extends CyberarmEngineStateV2 {
|
||||||
|
public init() {
|
||||||
|
addParallelState(new ParallelState(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
public exec() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
## TeamCode Module
|
|
||||||
|
|
||||||
Welcome!
|
|
||||||
|
|
||||||
This module, TeamCode, is the place where you will write/paste the code for your team's
|
|
||||||
robot controller App. This module is currently empty (a clean slate) but the
|
|
||||||
process for adding OpModes is straightforward.
|
|
||||||
|
|
||||||
## Creating your own OpModes
|
|
||||||
|
|
||||||
The easiest way to create your own OpMode is to copy a Sample OpMode and make it your own.
|
|
||||||
|
|
||||||
Sample opmodes exist in the FtcRobotController module.
|
|
||||||
To locate these samples, find the FtcRobotController module in the "Project/Android" tab.
|
|
||||||
|
|
||||||
Expand the following tree elements:
|
|
||||||
FtcRobotController / java / org.firstinspires.ftc.robotcontroller / external / samples
|
|
||||||
|
|
||||||
A range of different samples classes can be seen in this folder.
|
|
||||||
The class names follow a naming convention which indicates the purpose of each class.
|
|
||||||
The full description of this convention is found in the samples/sample_convention.md file.
|
|
||||||
|
|
||||||
A brief synopsis of the naming convention is given here:
|
|
||||||
The prefix of the name will be one of the following:
|
|
||||||
|
|
||||||
* Basic: This is a minimally functional OpMode used to illustrate the skeleton/structure
|
|
||||||
of a particular style of OpMode. These are bare bones examples.
|
|
||||||
* Sensor: This is a Sample OpMode that shows how to use a specific sensor.
|
|
||||||
It is not intended as a functioning robot, it is simply showing the minimal code
|
|
||||||
required to read and display the sensor values.
|
|
||||||
* Hardware: This is not an actual OpMode, but a helper class that is used to describe
|
|
||||||
one particular robot's hardware devices: eg: for a Pushbot. Look at any
|
|
||||||
Pushbot sample to see how this can be used in an OpMode.
|
|
||||||
Teams can copy one of these to create their own robot definition.
|
|
||||||
* Pushbot: This is a Sample OpMode that uses the Pushbot robot structure as a base.
|
|
||||||
* Concept: This is a sample OpMode that illustrates performing a specific function or concept.
|
|
||||||
These may be complex, but their operation should be explained clearly in the comments,
|
|
||||||
or the header should reference an external doc, guide or tutorial.
|
|
||||||
* Library: This is a class, or set of classes used to implement some strategy.
|
|
||||||
These will typically NOT implement a full OpMode. Instead they will be included
|
|
||||||
by an OpMode to provide some stand-alone capability.
|
|
||||||
|
|
||||||
Once you are familiar with the range of samples available, you can choose one to be the
|
|
||||||
basis for your own robot. In all cases, the desired sample(s) needs to be copied into
|
|
||||||
your TeamCode module to be used.
|
|
||||||
|
|
||||||
This is done inside Android Studio directly, using the following steps:
|
|
||||||
|
|
||||||
1) Locate the desired sample class in the Project/Android tree.
|
|
||||||
|
|
||||||
2) Right click on the sample class and select "Copy"
|
|
||||||
|
|
||||||
3) Expand the TeamCode / java folder
|
|
||||||
|
|
||||||
4) Right click on the org.firstinspires.ftc.teamcode folder and select "Paste"
|
|
||||||
|
|
||||||
5) You will be prompted for a class name for the copy.
|
|
||||||
Choose something meaningful based on the purpose of this class.
|
|
||||||
Start with a capital letter, and remember that there may be more similar classes later.
|
|
||||||
|
|
||||||
Once your copy has been created, you should prepare it for use on your robot.
|
|
||||||
This is done by adjusting the OpMode's name, and enabling it to be displayed on the
|
|
||||||
Driver Station's OpMode list.
|
|
||||||
|
|
||||||
Each OpMode sample class begins with several lines of code like the ones shown below:
|
|
||||||
|
|
||||||
```
|
|
||||||
@TeleOp(name="Template: Linear OpMode", group="Linear Opmode")
|
|
||||||
@Disabled
|
|
||||||
```
|
|
||||||
|
|
||||||
The name that will appear on the driver station's "opmode list" is defined by the code:
|
|
||||||
``name="Template: Linear OpMode"``
|
|
||||||
You can change what appears between the quotes to better describe your opmode.
|
|
||||||
The "group=" portion of the code can be used to help organize your list of OpModes.
|
|
||||||
|
|
||||||
As shown, the current OpMode will NOT appear on the driver station's OpMode list because of the
|
|
||||||
``@Disabled`` annotation which has been included.
|
|
||||||
This line can simply be deleted , or commented out, to make the OpMode visible.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## ADVANCED Multi-Team App management: Cloning the TeamCode Module
|
|
||||||
|
|
||||||
In some situations, you have multiple teams in your club and you want them to all share
|
|
||||||
a common code organization, with each being able to *see* the others code but each having
|
|
||||||
their own team module with their own code that they maintain themselves.
|
|
||||||
|
|
||||||
In this situation, you might wish to clone the TeamCode module, once for each of these teams.
|
|
||||||
Each of the clones would then appear along side each other in the Android Studio module list,
|
|
||||||
together with the FtcRobotController module (and the original TeamCode module).
|
|
||||||
|
|
||||||
Selective Team phones can then be programmed by selecting the desired Module from the pulldown list
|
|
||||||
prior to clicking to the green Run arrow.
|
|
||||||
|
|
||||||
Warning: This is not for the inexperienced Software developer.
|
|
||||||
You will need to be comfortable with File manipulations and managing Android Studio Modules.
|
|
||||||
These changes are performed OUTSIDE of Android Studios, so close Android Studios before you do this.
|
|
||||||
|
|
||||||
Also.. Make a full project backup before you start this :)
|
|
||||||
|
|
||||||
To clone TeamCode, do the following:
|
|
||||||
|
|
||||||
Note: Some names start with "Team" and others start with "team". This is intentional.
|
|
||||||
|
|
||||||
1) Using your operating system file management tools, copy the whole "TeamCode"
|
|
||||||
folder to a sibling folder with a corresponding new name, eg: "Team0417".
|
|
||||||
|
|
||||||
2) In the new Team0417 folder, delete the TeamCode.iml file.
|
|
||||||
|
|
||||||
3) the new Team0417 folder, rename the "src/main/java/org/firstinspires/ftc/teamcode" folder
|
|
||||||
to a matching name with a lowercase 'team' eg: "team0417".
|
|
||||||
|
|
||||||
4) In the new Team0417/src/main folder, edit the "AndroidManifest.xml" file, change the line that contains
|
|
||||||
package="org.firstinspires.ftc.teamcode"
|
|
||||||
to be
|
|
||||||
package="org.firstinspires.ftc.team0417"
|
|
||||||
|
|
||||||
5) Add: include ':Team0417' to the "/settings.gradle" file.
|
|
||||||
|
|
||||||
6) Open up Android Studios and clean out any old files by using the menu to "Build/Clean Project""
|
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.Config;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.Settings;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.TAC;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ActionDeserializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ActionSerializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigDeserializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigSerializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigurationDeserializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigurationSerializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.GroupDeserializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.GroupSerializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.PresetsDeserializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.PresetsSerializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.SettingsDeserializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.SettingsSerializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.VariableDeserializer;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.serializers.VariableSerializer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
|
|
||||||
|
public class TimeCraftersConfiguration {
|
||||||
|
private static final String TAG = "TCT|TCConfig";
|
||||||
|
private Config config;
|
||||||
|
|
||||||
|
public TimeCraftersConfiguration() {
|
||||||
|
Settings settings = loadSettings();
|
||||||
|
this.config = loadConfig(settings.config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeCraftersConfiguration(String configName) {
|
||||||
|
this.config = loadConfig(configName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Group group(String groupName) {
|
||||||
|
for (final Group group : config.getGroups()) {
|
||||||
|
if (group.name.trim().equals(groupName.trim())) {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw(new RuntimeException("Failed to find a group named:\"" + groupName.trim() + "\" in config \"" + config.getName() + "\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action action(String groupName, String actionName) {
|
||||||
|
final Group group = group(groupName);
|
||||||
|
|
||||||
|
for (Action action : group.getActions()) {
|
||||||
|
if (action.name.trim().equals(actionName.trim())) {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw(new RuntimeException("Failed to find an action named:\"" + actionName.trim() + "\" in group \"" + groupName.trim() + "\" in config \"" + config.getName() + "\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Variable variable(String groupName, String actionName, String variableName) {
|
||||||
|
final Action action = action(groupName, groupName);
|
||||||
|
|
||||||
|
for (Variable variable : action.getVariables()) {
|
||||||
|
if (variable.name.trim().equals(variableName.trim())) {
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw(new RuntimeException("Failed to find a variable named \"" + variableName.trim() + "\" in action:\"" + actionName.trim() +
|
||||||
|
"\" in group \"" + groupName.trim() + "\" in config \"" + config.getName() + "\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Settings loadSettings() {
|
||||||
|
File settingsFile = new File(TAC.SETTINGS_PATH);
|
||||||
|
|
||||||
|
if (!settingsFile.exists()) {
|
||||||
|
throw( new RuntimeException("Unable to load settings.json, file does not exist!") );
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return gsonForSettings().fromJson(new FileReader(settingsFile), Settings.class);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw( new RuntimeException("Unable to load settings.json") );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Config loadConfig(String name) {
|
||||||
|
if (name.equals("")) {
|
||||||
|
throw(new RuntimeException("Cannot load a config with an empty name!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
String path = TAC.CONFIGS_PATH + File.separator + name + ".json";
|
||||||
|
File configFile = new File(path);
|
||||||
|
|
||||||
|
if (configFile.exists() && configFile.isFile()) {
|
||||||
|
try {
|
||||||
|
Config config = gsonForConfig().fromJson(new FileReader(configFile), Config.class);
|
||||||
|
config.setName(name);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw(new RuntimeException("Unable to find a config file named \"" + name + "\""));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw(new RuntimeException("Unable to find a config file named \"" + name + "\""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Gson gsonForSettings() {
|
||||||
|
return new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Settings.class, new SettingsSerializer())
|
||||||
|
.registerTypeAdapter(Settings.class, new SettingsDeserializer())
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gson gsonForConfig() {
|
||||||
|
return new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Config.class, new ConfigSerializer())
|
||||||
|
.registerTypeAdapter(Config.class, new ConfigDeserializer())
|
||||||
|
|
||||||
|
.registerTypeAdapter(Configuration.class, new ConfigurationSerializer())
|
||||||
|
.registerTypeAdapter(Configuration.class, new ConfigurationDeserializer())
|
||||||
|
|
||||||
|
.registerTypeAdapter(Group.class, new GroupSerializer())
|
||||||
|
.registerTypeAdapter(Group.class, new GroupDeserializer())
|
||||||
|
|
||||||
|
.registerTypeAdapter(Action.class, new ActionSerializer())
|
||||||
|
.registerTypeAdapter(Action.class, new ActionDeserializer())
|
||||||
|
|
||||||
|
.registerTypeAdapter(Variable.class, new VariableSerializer())
|
||||||
|
.registerTypeAdapter(Variable.class, new VariableDeserializer())
|
||||||
|
|
||||||
|
.registerTypeAdapter(Presets.class, new PresetsSerializer())
|
||||||
|
.registerTypeAdapter(Presets.class, new PresetsDeserializer())
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class Config {
|
||||||
|
private String name;
|
||||||
|
private Configuration configuration;
|
||||||
|
private ArrayList<Group> groups;
|
||||||
|
private Presets presets;
|
||||||
|
|
||||||
|
public Config(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.configuration = new Configuration(new Date(), new Date(), TAC.CONFIG_SPEC_VERSION, 0);
|
||||||
|
groups = new ArrayList<>();
|
||||||
|
presets = new Presets(new ArrayList<Group>(), new ArrayList<Action>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Config(Configuration configuration, ArrayList<Group> groups, Presets presets) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.groups = groups;
|
||||||
|
this.presets = presets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() { return name; }
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
|
||||||
|
public Configuration getConfiguration() {
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Presets getPresets() {
|
||||||
|
return presets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Group> getGroups() {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend;
|
||||||
|
|
||||||
|
public class Settings {
|
||||||
|
public String hostname, config;
|
||||||
|
public int port;
|
||||||
|
|
||||||
|
public Settings(String hostname, int port, String config) {
|
||||||
|
this.hostname = hostname;
|
||||||
|
this.port = port;
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class TAC {
|
||||||
|
// TODO: Update filesystem handling
|
||||||
|
public static final String ROOT_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "TimeCrafters_Configuration_Tool",
|
||||||
|
CONFIGS_PATH = ROOT_PATH + File.separator + "/configs",
|
||||||
|
SETTINGS_PATH = ROOT_PATH + File.separator + "settings.json";
|
||||||
|
|
||||||
|
public static final int CONFIG_SPEC_VERSION = 2;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Action {
|
||||||
|
public String name, comment;
|
||||||
|
public boolean enabled;
|
||||||
|
private ArrayList<Variable> variables;
|
||||||
|
|
||||||
|
public Action(String name, String comment, boolean enabled, ArrayList<Variable> variables) {
|
||||||
|
this.name = name;
|
||||||
|
this.comment = comment;
|
||||||
|
this.enabled = enabled;
|
||||||
|
this.variables = variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Variable> getVariables() { return variables; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class Configuration {
|
||||||
|
public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z";
|
||||||
|
|
||||||
|
public Date createdAt, updatedAt;
|
||||||
|
private int specVersion;
|
||||||
|
public int revision;
|
||||||
|
|
||||||
|
public Configuration(Date createdAt, Date updatedAt, int specVersion, int revision) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
this.specVersion = specVersion;
|
||||||
|
this.revision = revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSpecVersion() { return specVersion; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Group {
|
||||||
|
public String name;
|
||||||
|
private ArrayList<Action> actions;
|
||||||
|
|
||||||
|
public Group(String name, ArrayList<Action> actions) {
|
||||||
|
this.name = name;
|
||||||
|
this.actions = actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean nameIsUnique(ArrayList<Group> groups, String name) {
|
||||||
|
for (Group group: groups) {
|
||||||
|
if (group.name.equals(name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Action> getActions() {
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class Presets {
|
||||||
|
private ArrayList<Group> groups;
|
||||||
|
private ArrayList<Action> actions;
|
||||||
|
|
||||||
|
public Presets(ArrayList<Group> groups, ArrayList<Action> actions) {
|
||||||
|
this.groups = groups;
|
||||||
|
this.actions = actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Group> getGroups() {
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Action> getActions() {
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
|
||||||
|
|
||||||
|
public class Variable {
|
||||||
|
public String name;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public Variable(String name, String value) {
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String rawValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T value() {
|
||||||
|
return valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static public <T> T valueOf(String value) {
|
||||||
|
String[] split = value.split("x", 2);
|
||||||
|
// Log.d("Variable", "valueOf split: " + Arrays.toString(split));
|
||||||
|
|
||||||
|
switch (split[0]) {
|
||||||
|
case "B": {
|
||||||
|
return (T) Boolean.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "D": {
|
||||||
|
return (T) Double.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "F": {
|
||||||
|
return (T) Float.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "I": {
|
||||||
|
return (T) Integer.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "L": {
|
||||||
|
return (T) Long.valueOf(split[(split.length-1)]);
|
||||||
|
}
|
||||||
|
case "S": {
|
||||||
|
String string = "";
|
||||||
|
int i = 0;
|
||||||
|
for(String str : split) {
|
||||||
|
if (i == 0) { i++; continue; }
|
||||||
|
|
||||||
|
string += str;
|
||||||
|
}
|
||||||
|
return (T) string;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public String typeOf(String value) {
|
||||||
|
String[] split = value.split("x");
|
||||||
|
|
||||||
|
switch (split[0]) {
|
||||||
|
case "B": {
|
||||||
|
return "Boolean";
|
||||||
|
}
|
||||||
|
case "D": {
|
||||||
|
return "Double";
|
||||||
|
}
|
||||||
|
case "F": {
|
||||||
|
return "Float";
|
||||||
|
}
|
||||||
|
case "I": {
|
||||||
|
return "Integer";
|
||||||
|
}
|
||||||
|
case "L": {
|
||||||
|
return "Long";
|
||||||
|
}
|
||||||
|
case "S": {
|
||||||
|
return "String";
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return "=!UNKNOWN!=";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ActionDeserializer implements JsonDeserializer<Action> {
|
||||||
|
@Override
|
||||||
|
public Action deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
|
||||||
|
final String name = jsonObject.get("name").getAsString();
|
||||||
|
final String comment = jsonObject.get("comment").getAsString();
|
||||||
|
final boolean enabled = jsonObject.get("enabled").getAsBoolean();
|
||||||
|
Variable[] variablesArray = context.deserialize(jsonObject.get("variables"), Variable[].class);
|
||||||
|
|
||||||
|
List<Variable> variablesList = Arrays.asList(variablesArray);
|
||||||
|
ArrayList<Variable> variables = new ArrayList<>(variablesList);
|
||||||
|
|
||||||
|
return new Action(name, comment, enabled, variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class ActionSerializer implements JsonSerializer<Action> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Action action, Type type, JsonSerializationContext context) {
|
||||||
|
JsonObject container = new JsonObject();
|
||||||
|
|
||||||
|
container.add("name", new JsonPrimitive(action.name));
|
||||||
|
container.add("comment", new JsonPrimitive(action.comment));
|
||||||
|
container.add("enabled", new JsonPrimitive(action.enabled));
|
||||||
|
container.add("variables", context.serialize(action.getVariables().toArray(), Variable[].class));
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.Config;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ConfigDeserializer implements JsonDeserializer<Config> {
|
||||||
|
@Override
|
||||||
|
public Config deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
JsonObject data = jsonObject.get("data").getAsJsonObject();
|
||||||
|
|
||||||
|
Configuration configuration = context.deserialize(jsonObject.get("config"), Configuration.class);
|
||||||
|
Group[] groupsArray = context.deserialize(data.get("groups"), Group[].class);
|
||||||
|
List<Group> groupsList = Arrays.asList(groupsArray);
|
||||||
|
ArrayList<Group> groups = new ArrayList<>(groupsList);
|
||||||
|
|
||||||
|
Presets presets = context.deserialize(data.get("presets"), Presets.class);
|
||||||
|
|
||||||
|
return new Config(configuration, groups, presets);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.Config;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class ConfigSerializer implements JsonSerializer<Config> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Config config, Type type, JsonSerializationContext context) {
|
||||||
|
JsonObject container = new JsonObject();
|
||||||
|
JsonObject result = new JsonObject();
|
||||||
|
JsonObject presets = new JsonObject();
|
||||||
|
container.add("config", context.serialize(config.getConfiguration(), Configuration.class));
|
||||||
|
result.add("groups", context.serialize(config.getGroups().toArray(), Group[].class));
|
||||||
|
|
||||||
|
presets.add("groups", context.serialize(config.getPresets().getGroups().toArray(), Group[].class));
|
||||||
|
presets.add("actions", context.serialize(config.getPresets().getActions().toArray(), Action[].class));
|
||||||
|
|
||||||
|
result.add("presets", presets);
|
||||||
|
container.add("data", result);
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class ConfigurationDeserializer implements JsonDeserializer<Configuration> {
|
||||||
|
@Override
|
||||||
|
public Configuration deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject config = json.getAsJsonObject();
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat(Configuration.DATE_FORMAT);
|
||||||
|
Date createdAt = new Date();
|
||||||
|
Date updatedAt = new Date();
|
||||||
|
try {
|
||||||
|
createdAt = dateFormat.parse(config.get("created_at").getAsString());
|
||||||
|
updatedAt = dateFormat.parse(config.get("updated_at").getAsString());
|
||||||
|
} catch (ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
final int spec_version = config.get("spec_version").getAsInt();
|
||||||
|
final int revision = config.get("revision").getAsInt();
|
||||||
|
|
||||||
|
return new Configuration(createdAt, updatedAt, spec_version, revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
public class ConfigurationSerializer implements JsonSerializer<Configuration> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Configuration configuration, Type type, JsonSerializationContext context) {
|
||||||
|
JsonObject container = new JsonObject();
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat(Configuration.DATE_FORMAT);
|
||||||
|
|
||||||
|
container.add("created_at", new JsonPrimitive(dateFormat.format(configuration.createdAt)));
|
||||||
|
container.add("updated_at", new JsonPrimitive(dateFormat.format(configuration.updatedAt)));
|
||||||
|
container.add("spec_version", new JsonPrimitive(configuration.getSpecVersion()));
|
||||||
|
container.add("revision", new JsonPrimitive(configuration.revision));
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GroupDeserializer implements JsonDeserializer<Group> {
|
||||||
|
@Override
|
||||||
|
public Group deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
|
||||||
|
final String name = jsonObject.get("name").getAsString();
|
||||||
|
Action[] actionsArray = context.deserialize(jsonObject.get("actions"), Action[].class);
|
||||||
|
|
||||||
|
List<Action> actionsList = Arrays.asList(actionsArray);
|
||||||
|
ArrayList<Action> actions = new ArrayList<>(actionsList);
|
||||||
|
|
||||||
|
return new Group(name, actions);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class GroupSerializer implements JsonSerializer<Group> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Group group, Type type, JsonSerializationContext context) {
|
||||||
|
JsonObject container = new JsonObject();
|
||||||
|
|
||||||
|
container.add("name", new JsonPrimitive(group.name));
|
||||||
|
container.add("actions", context.serialize(group.getActions().toArray(), Action[].class));
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PresetsDeserializer implements JsonDeserializer<Presets> {
|
||||||
|
@Override
|
||||||
|
public Presets deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
|
||||||
|
Group[] GroupsArray = context.deserialize(jsonObject.get("groups"), Group[].class);
|
||||||
|
Action[] actionsArray = context.deserialize(jsonObject.get("actions"), Action[].class);
|
||||||
|
|
||||||
|
List<Group> groupsList = Arrays.asList(GroupsArray);
|
||||||
|
ArrayList<Group> groups = new ArrayList<>(groupsList);
|
||||||
|
List<Action> actionsList = Arrays.asList(actionsArray);
|
||||||
|
ArrayList<Action> actions = new ArrayList<>(actionsList);
|
||||||
|
|
||||||
|
return new Presets(groups, actions);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class PresetsSerializer implements JsonSerializer<Presets> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Presets presets, Type type, JsonSerializationContext context) {
|
||||||
|
JsonObject container = new JsonObject();
|
||||||
|
|
||||||
|
container.add("groups", context.serialize(presets.getGroups().toArray(), Group[].class));
|
||||||
|
container.add("actions", context.serialize(presets.getActions().toArray(), Action[].class));
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.Settings;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class SettingsDeserializer implements JsonDeserializer<Settings> {
|
||||||
|
@Override
|
||||||
|
public Settings deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
JsonObject data = jsonObject.get("data").getAsJsonObject();
|
||||||
|
|
||||||
|
return new Settings(
|
||||||
|
data.get("hostname").getAsString(),
|
||||||
|
data.get("port").getAsInt(),
|
||||||
|
data.get("config").getAsString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.Settings;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class SettingsSerializer implements JsonSerializer<Settings> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Settings settings, Type type, JsonSerializationContext context) {
|
||||||
|
JsonObject container = new JsonObject();
|
||||||
|
JsonObject result = new JsonObject();
|
||||||
|
result.add("hostname", new JsonPrimitive(settings.hostname));
|
||||||
|
result.add("port", new JsonPrimitive(settings.port));
|
||||||
|
result.add("config", new JsonPrimitive(settings.config));
|
||||||
|
|
||||||
|
container.add("data", result);
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class VariableDeserializer implements JsonDeserializer<Variable> {
|
||||||
|
@Override
|
||||||
|
public Variable deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
|
||||||
|
final String name = jsonObject.get("name").getAsString();
|
||||||
|
final String value = jsonObject.get("value").getAsString();
|
||||||
|
|
||||||
|
return new Variable(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
|
||||||
|
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
public class VariableSerializer implements JsonSerializer<Variable> {
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(Variable variable, Type type, JsonSerializationContext context) {
|
||||||
|
JsonObject container = new JsonObject();
|
||||||
|
|
||||||
|
container.add("name", new JsonPrimitive(variable.name));
|
||||||
|
container.add("value", new JsonPrimitive(variable.rawValue()));
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.timecrafters.UltimateGoal.HardwareTesting;
|
||||||
|
|
||||||
|
import org.cyberarm.engine.V2.CyberarmState;
|
||||||
|
import org.timecrafters.UltimateGoal.Robot;
|
||||||
|
|
||||||
|
|
||||||
|
public class ControlHubTest extends CyberarmState {
|
||||||
|
|
||||||
|
private Robot robot;
|
||||||
|
private float angle = 0;
|
||||||
|
|
||||||
|
public ControlHubTest(Robot robot) {
|
||||||
|
this.robot = robot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exec() {
|
||||||
|
angle = robot.imu.getAngularOrientation().firstAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void telemetry() {
|
||||||
|
engine.telemetry.addLine("Greetings");
|
||||||
|
engine.telemetry.addData("Angle", angle);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package org.timecrafters.UltimateGoal.HardwareTesting;
|
||||||
|
|
||||||
|
import org.cyberarm.engine.V2.CyberarmState;
|
||||||
|
import org.timecrafters.UltimateGoal.Robot;
|
||||||
|
|
||||||
|
|
||||||
|
public class EncoderTest extends CyberarmState {
|
||||||
|
|
||||||
|
private Robot robot;
|
||||||
|
private int ticksLeft;
|
||||||
|
private int ticksRight;
|
||||||
|
private double biasLeft = 0;
|
||||||
|
private double biasRight = 0;
|
||||||
|
|
||||||
|
public EncoderTest(Robot robot) {
|
||||||
|
this.robot = robot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exec() {
|
||||||
|
robot.updateLocation();
|
||||||
|
|
||||||
|
if (runTime() < 3000) {
|
||||||
|
robot.setDrivePower(0.5, 0.5);
|
||||||
|
|
||||||
|
ticksLeft=robot.encoderLeft.getCurrentPosition();
|
||||||
|
ticksRight=robot.encoderRight.getCurrentPosition();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
robot.encoderLeft.setPower(0.0);
|
||||||
|
robot.encoderRight.setPower(0.0);
|
||||||
|
|
||||||
|
double ticksExtreme;
|
||||||
|
if (Math.abs(ticksLeft) < Math.abs(ticksRight)) {
|
||||||
|
ticksExtreme = ticksLeft;
|
||||||
|
} else {
|
||||||
|
ticksExtreme = ticksRight;
|
||||||
|
}
|
||||||
|
biasLeft = ticksExtreme/ticksLeft;
|
||||||
|
biasRight = ticksExtreme/ticksRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void telemetry() {
|
||||||
|
engine.telemetry.addLine("Biases");
|
||||||
|
engine.telemetry.addData("Left", biasLeft);
|
||||||
|
engine.telemetry.addData("Right", biasRight);
|
||||||
|
engine.telemetry.addLine();
|
||||||
|
engine.telemetry.addLine("Latency Values");
|
||||||
|
engine.telemetry.addData("Y", robot.getLocationY());
|
||||||
|
engine.telemetry.addData("X", robot.getLocationX());
|
||||||
|
engine.telemetry.addLine();
|
||||||
|
engine.telemetry.addData("Rotation", robot.getRotation());
|
||||||
|
engine.telemetry.addLine();
|
||||||
|
engine.telemetry.addLine("Actual Values");
|
||||||
|
engine.telemetry.addData("Left", ticksLeft);
|
||||||
|
engine.telemetry.addData("Right", ticksRight);
|
||||||
|
// engine.telemetry.addLine("");
|
||||||
|
// engine.telemetry.addData("Front", robot.encoderFront);
|
||||||
|
// engine.telemetry.addData("Back", robot.encoderBack);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.timecrafters.UltimateGoal.HardwareTesting;
|
||||||
|
|
||||||
|
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
|
||||||
|
|
||||||
|
import org.cyberarm.engine.V2.CyberarmEngine;
|
||||||
|
import org.timecrafters.UltimateGoal.Robot;
|
||||||
|
|
||||||
|
@TeleOp (name = "Encoder test", group = "test")
|
||||||
|
public class TestingEngine extends CyberarmEngine {
|
||||||
|
|
||||||
|
private Robot robot;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
robot = new Robot(hardwareMap);
|
||||||
|
robot.initHardware();
|
||||||
|
super.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup() {
|
||||||
|
addState(new EncoderTest(robot));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
103
TeamCode/src/main/java/org/timecrafters/UltimateGoal/Robot.java
Normal file
103
TeamCode/src/main/java/org/timecrafters/UltimateGoal/Robot.java
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package org.timecrafters.UltimateGoal;
|
||||||
|
|
||||||
|
import com.qualcomm.hardware.bosch.BNO055IMU;
|
||||||
|
import com.qualcomm.robotcore.hardware.DcMotor;
|
||||||
|
import com.qualcomm.robotcore.hardware.DcMotorSimple;
|
||||||
|
import com.qualcomm.robotcore.hardware.HardwareMap;
|
||||||
|
|
||||||
|
import org.cyberarm.NeXT.StateConfiguration;
|
||||||
|
|
||||||
|
public class Robot {
|
||||||
|
|
||||||
|
private HardwareMap hardwareMap;
|
||||||
|
|
||||||
|
public Robot(HardwareMap hardwareMap) {
|
||||||
|
this.hardwareMap = hardwareMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateConfiguration stateConfiguration = new StateConfiguration();
|
||||||
|
public BNO055IMU imu;
|
||||||
|
|
||||||
|
//drive system
|
||||||
|
|
||||||
|
public DcMotor encoderFront;
|
||||||
|
public DcMotor encoderLeft;
|
||||||
|
public DcMotor encoderBack;
|
||||||
|
public DcMotor encoderRight;
|
||||||
|
|
||||||
|
double BIAS_LEFT = 1.0;
|
||||||
|
double BIAS_RIGHT = 0.6815;
|
||||||
|
|
||||||
|
//Robot Localizatoin
|
||||||
|
private double locationX;
|
||||||
|
private double locationY;
|
||||||
|
private float rotation;
|
||||||
|
|
||||||
|
private int encoderFrontPrevious = 0;
|
||||||
|
private int encoderLeftPrevious = 0;
|
||||||
|
private int encoderBackPrevious = 0;
|
||||||
|
private int encoderRightPrevious = 0;
|
||||||
|
private float rotationPrevious = 0;
|
||||||
|
|
||||||
|
public void initHardware() {
|
||||||
|
imu = hardwareMap.get(BNO055IMU.class, "imu");
|
||||||
|
// encoderFront = hardwareMap.dcMotor.get("encoderFront");
|
||||||
|
encoderLeft = hardwareMap.dcMotor.get("encoderLeft");
|
||||||
|
// encoderBack = hardwareMap.dcMotor.get("encoderBack");
|
||||||
|
encoderRight = hardwareMap.dcMotor.get("encoderRight");
|
||||||
|
|
||||||
|
encoderLeft.setDirection(DcMotorSimple.Direction.REVERSE);
|
||||||
|
|
||||||
|
encoderLeft.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||||
|
encoderRight.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
|
||||||
|
|
||||||
|
BNO055IMU.Parameters parameters = new BNO055IMU.Parameters();
|
||||||
|
|
||||||
|
parameters.mode = BNO055IMU.SensorMode.IMU;
|
||||||
|
parameters.angleUnit = BNO055IMU.AngleUnit.DEGREES;
|
||||||
|
parameters.accelUnit = BNO055IMU.AccelUnit.METERS_PERSEC_PERSEC;
|
||||||
|
parameters.loggingEnabled = false;
|
||||||
|
|
||||||
|
imu.initialize(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrivePower(double powerLeft, double powerRight){
|
||||||
|
encoderLeft.setPower(powerLeft * BIAS_LEFT);
|
||||||
|
encoderRight.setPower(powerRight * BIAS_RIGHT);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLocation(){
|
||||||
|
rotation = imu.getAngularOrientation().firstAngle;
|
||||||
|
float rotationChange = rotation - rotationPrevious;
|
||||||
|
int encoderLeftCurrent = encoderLeft.getCurrentPosition();
|
||||||
|
int encoderRightCurrent = encoderRight.getCurrentPosition();
|
||||||
|
double encoderLeftChange = encoderLeftCurrent - encoderLeftPrevious;
|
||||||
|
double encoderRightChange = encoderRightCurrent - encoderRightPrevious;
|
||||||
|
|
||||||
|
encoderLeftPrevious = encoderLeftCurrent;
|
||||||
|
encoderRightPrevious = encoderRightCurrent;
|
||||||
|
rotationPrevious = rotation;
|
||||||
|
|
||||||
|
double average = (encoderLeftChange+encoderRightChange)/2;
|
||||||
|
|
||||||
|
double xChange = average * (Math.sin(Math.toRadians(rotationChange)));
|
||||||
|
double yChange = average * (Math.cos(Math.toRadians(rotationChange)));
|
||||||
|
|
||||||
|
locationX += xChange;
|
||||||
|
locationY += yChange;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRotation() {
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLocationX() {
|
||||||
|
return locationX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLocationY() {
|
||||||
|
return locationY;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user