Compare commits
10 Commits
0c5775560c
...
ec63a65ba3
| Author | SHA1 | Date | |
|---|---|---|---|
| ec63a65ba3 | |||
| ec89107262 | |||
| 8dca828cf3 | |||
| 2da337b8a9 | |||
| 17be4149db | |||
| f9aadbcbe9 | |||
| bd3402fc39 | |||
| 747bde4aa6 | |||
| 655439461a | |||
| b9452cd598 |
@@ -1,19 +1,18 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.Process;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
import lib.cli.TermHandle;
|
|
||||||
import lib.cli.CLIApp;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
using Lambda;
|
using Lambda;
|
||||||
|
|
||||||
class Disk extends CLIApp {
|
class Disk implements Process {
|
||||||
|
private var handle:ProcessHandle;
|
||||||
private var handle:TermHandle;
|
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function invoke(handle:TermHandle):Future<Bool> {
|
public function run(handle:ProcessHandle):Void {
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
var subcommand = handle.args[0];
|
var subcommand = handle.args[0];
|
||||||
var driveAddr:Null<String> = handle.args[1];
|
var driveAddr:Null<String> = handle.args[1];
|
||||||
@@ -27,12 +26,12 @@ class Disk extends CLIApp {
|
|||||||
|
|
||||||
if (drive.isDiskPresent()){
|
if (drive.isDiskPresent()){
|
||||||
if (drive.hasAudio()){
|
if (drive.hasAudio()){
|
||||||
handle.writeLn('${addr} => ${label} [AUDIO]');
|
handle.writeLine('${addr} => ${label} [AUDIO]');
|
||||||
}else{
|
}else{
|
||||||
handle.writeLn('${addr} => ${label} (${id})');
|
handle.writeLine('${addr} => ${label} (${id})');
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
handle.writeLn('${addr} => [NO DISK]');
|
handle.writeLine('${addr} => [NO DISK]');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -41,18 +40,15 @@ class Disk extends CLIApp {
|
|||||||
var drive = Peripheral.instance.getDrive(driveAddr);
|
var drive = Peripheral.instance.getDrive(driveAddr);
|
||||||
|
|
||||||
if (drive == null){
|
if (drive == null){
|
||||||
handle.writeLn("Drive not found: " + driveAddr);
|
handle.writeLine("Drive not found: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drive.isDiskPresent()){
|
if (!drive.isDiskPresent()){
|
||||||
handle.writeLn("No disk in drive: " + driveAddr);
|
handle.writeLine("No disk in drive: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drive.hasAudio()){
|
if (!drive.hasAudio()){
|
||||||
handle.writeLn("Disk in drive " + driveAddr + " does not have audio");
|
handle.writeLine("Disk in drive " + driveAddr + " does not have audio");
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drive.playAudio();
|
drive.playAudio();
|
||||||
@@ -60,18 +56,15 @@ class Disk extends CLIApp {
|
|||||||
var drive = Peripheral.instance.getDrive(driveAddr);
|
var drive = Peripheral.instance.getDrive(driveAddr);
|
||||||
|
|
||||||
if (drive == null){
|
if (drive == null){
|
||||||
handle.writeLn("Drive not found: " + driveAddr);
|
handle.writeLine("Drive not found: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drive.isDiskPresent()){
|
if (!drive.isDiskPresent()){
|
||||||
handle.writeLn("No disk in drive: " + driveAddr);
|
handle.writeLine("No disk in drive: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drive.hasAudio()){
|
if (!drive.hasAudio()){
|
||||||
handle.writeLn("Disk in drive: " + driveAddr + " does not have audio");
|
handle.writeLine("Disk in drive: " + driveAddr + " does not have audio");
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drive.stopAudio();
|
drive.stopAudio();
|
||||||
@@ -80,13 +73,11 @@ class Disk extends CLIApp {
|
|||||||
var drive = Peripheral.instance.getDrive(driveAddr);
|
var drive = Peripheral.instance.getDrive(driveAddr);
|
||||||
|
|
||||||
if (drive == null){
|
if (drive == null){
|
||||||
handle.writeLn("Drive not found: " + driveAddr);
|
handle.writeLine("Drive not found: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drive.isDiskPresent()){
|
if (!drive.isDiskPresent()){
|
||||||
handle.writeLn("No disk in drive: " + driveAddr);
|
handle.writeLine("No disk in drive: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drive.ejectDisk();
|
drive.ejectDisk();
|
||||||
@@ -95,43 +86,39 @@ class Disk extends CLIApp {
|
|||||||
var label:String = handle.args[2];
|
var label:String = handle.args[2];
|
||||||
|
|
||||||
if (drive == null){
|
if (drive == null){
|
||||||
handle.writeLn("Drive not found: " + driveAddr);
|
handle.writeLine("Drive not found: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drive.isDiskPresent()){
|
if (!drive.isDiskPresent()){
|
||||||
handle.writeLn("No disk in drive: " + driveAddr);
|
handle.writeLine("No disk in drive: " + driveAddr);
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (label == null || label == ""){
|
if (label == null || label == ""){
|
||||||
handle.writeLn(drive.getDiskLabel());
|
handle.writeLine(drive.getDiskLabel());
|
||||||
}else{
|
}else{
|
||||||
var err = drive.setDiskLabel(label);
|
var err = drive.setDiskLabel(label);
|
||||||
if (err != null){
|
if (err != null){
|
||||||
handle.writeLn("Failed to set lable");
|
handle.writeLine("Failed to set lable");
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "help":
|
case "help":
|
||||||
case null:
|
case null:
|
||||||
printHelp();
|
printHelp();
|
||||||
default:
|
default:
|
||||||
handle.writeLn("Unknown subcommand: " + subcommand);
|
handle.writeLine("Unknown subcommand: " + subcommand);
|
||||||
printHelp();
|
printHelp();
|
||||||
return Future.sync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Future.sync(true);
|
return handle.close(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function printHelp() {
|
private function printHelp() {
|
||||||
handle.writeLn("Usage: disk <subcommand> [args]");
|
handle.writeLine("Usage: disk <subcommand> [args]");
|
||||||
handle.writeLn("Subcommands:");
|
handle.writeLine("Subcommands:");
|
||||||
handle.writeLn(" ls");
|
handle.writeLine(" ls");
|
||||||
handle.writeLn(" play <drive>");
|
handle.writeLine(" play <drive>");
|
||||||
handle.writeLn(" stop <drive>");
|
handle.writeLine(" stop <drive>");
|
||||||
handle.writeLn(" eject <drive>");
|
handle.writeLine(" eject <drive>");
|
||||||
handle.writeLn(" label <drive> [label]");
|
handle.writeLine(" label <drive> [label]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.Process;
|
||||||
|
import kernel.gps.INS;
|
||||||
import lib.Pos3;
|
import lib.Pos3;
|
||||||
import lib.Vec.Vec3;
|
import lib.Vec.Vec3;
|
||||||
import lib.cli.TermHandle;
|
|
||||||
import lib.cli.CLIApp;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class GPS extends CLIApp {
|
class GPS implements Process {
|
||||||
private var handle:TermHandle;
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function invoke(handle: TermHandle):Future<Bool> {
|
public function run(handle: ProcessHandle):Void {
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
|
||||||
var subcommand = handle.args[0];
|
var subcommand = handle.args[0];
|
||||||
@@ -20,19 +21,37 @@ class GPS extends CLIApp {
|
|||||||
|
|
||||||
switch (subcommand) {
|
switch (subcommand) {
|
||||||
case "set":
|
case "set":
|
||||||
return Future.sync(setManuelPos(subcommand_args));
|
handle.close(setManuelPos(subcommand_args));
|
||||||
case "status":
|
case "status":
|
||||||
return Future.sync(getGPSStatus());
|
handle.close(getGPSStatus());
|
||||||
case "locate":
|
case "locate":
|
||||||
kernel.gps.GPS.instance.locate();
|
kernel.gps.GPS.instance.locate().handle((pos)->{
|
||||||
return Future.sync(true);
|
if (pos != null) {
|
||||||
|
handle.writeLine('Position x:${pos.x} y:${pos.y} z:${pos.z}');
|
||||||
|
handle.close(true);
|
||||||
|
} else {
|
||||||
|
handle.writeLine("Position not available");
|
||||||
|
handle.close(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
case "ins":
|
||||||
|
INS.instance.align().handle(()->{
|
||||||
|
handle.writeLine("INS aligned");
|
||||||
|
handle.close(true);
|
||||||
|
});
|
||||||
default:
|
default:
|
||||||
handle.writeLn("Unknown subcommand: " + subcommand);
|
handle.writeLine("Unknown subcommand: " + subcommand);
|
||||||
return Future.sync(false);
|
printHelp();
|
||||||
|
handle.close(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Future.sync(true);
|
private function printHelp(){
|
||||||
|
handle.writeLine("GPS commands:");
|
||||||
|
handle.writeLine("set <x> <y> <z> - set manual position");
|
||||||
|
handle.writeLine("status - get current position and accuracy");
|
||||||
|
handle.writeLine("locate - get current position");
|
||||||
|
handle.writeLine("ins - align INS");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setManuelPos(args: Array<String>): Bool {
|
private function setManuelPos(args: Array<String>): Bool {
|
||||||
@@ -51,19 +70,26 @@ class GPS extends CLIApp {
|
|||||||
|
|
||||||
var pos = kernel.gps.GPS.instance.getPosition();
|
var pos = kernel.gps.GPS.instance.getPosition();
|
||||||
if (pos != null) {
|
if (pos != null) {
|
||||||
handle.writeLn('Position x:${pos.x} y:${pos.y} z:${pos.z}');
|
handle.writeLine('Position x:${pos.x} y:${pos.y} z:${pos.z}');
|
||||||
} else {
|
} else {
|
||||||
handle.writeLn("Position not available");
|
handle.writeLine("Position not available");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var acc = kernel.gps.GPS.instance.getAccuracy();
|
var acc = kernel.gps.GPS.instance.getAccuracy();
|
||||||
if (acc == 1){
|
if (acc == 1){
|
||||||
handle.writeLn("Accuracy: Low");
|
handle.writeLine("Accuracy: Low");
|
||||||
} else if (acc == 2){
|
} else if (acc == 2){
|
||||||
handle.writeLn("Accuracy: Medium");
|
handle.writeLine("Accuracy: Medium");
|
||||||
} else if (acc == 3){
|
} else if (acc == 3){
|
||||||
handle.writeLn("Accuracy: High");
|
handle.writeLine("Accuracy: High");
|
||||||
|
}
|
||||||
|
|
||||||
|
var ins = INS.instance.getHeading();
|
||||||
|
if (ins != null) {
|
||||||
|
handle.writeLine('INS heading: ${ins.x} y:${ins.y} z:${ins.z}');
|
||||||
|
} else {
|
||||||
|
handle.writeLine("INS heading not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
import lib.cli.TermHandle;
|
import kernel.ps.ProcessHandle;
|
||||||
import lib.cli.CLIApp;
|
import kernel.ps.Process;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class HelloWorld extends CLIApp {
|
class HelloWorld implements Process {
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function invoke(handle: TermHandle):Future<Bool> {
|
public function run(handle:ProcessHandle) {
|
||||||
var world:String = "world";
|
handle.write("Hello World!");
|
||||||
if (handle.args.length > 0) {
|
handle.close();
|
||||||
world = handle.args[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
handle.write('Hello, $world!');
|
|
||||||
return Future.sync(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.Process;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import lib.MathI;
|
import lib.MathI;
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
@@ -8,24 +10,22 @@ import lib.ui.UIApp;
|
|||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class KernelLog extends UIApp{
|
class KernelLog implements Process {
|
||||||
private var ctx:WindowContext;
|
private var handle: ProcessHandle;
|
||||||
private var exitTrigger: Bool -> Void;
|
private var ctx: WindowContext;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function invoke(context:WindowContext):Future<Bool> {
|
public function run(handle: ProcessHandle):Void {
|
||||||
this.ctx = context;
|
this.handle = handle;
|
||||||
|
|
||||||
|
var statelessCtx = handle.createStatelessWindowContext();
|
||||||
|
this.ctx = statelessCtx.ctx;
|
||||||
|
|
||||||
|
statelessCtx.setRenderFunc(this.render);
|
||||||
|
|
||||||
Log.instance.onLog.handle(()->{
|
Log.instance.onLog.handle(()->{
|
||||||
render();
|
statelessCtx.requestRender();
|
||||||
});
|
|
||||||
|
|
||||||
render();
|
|
||||||
|
|
||||||
return new Future<Bool>(cb -> {
|
|
||||||
this.exitTrigger = cb;
|
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.Process;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
import kernel.net.Routing;
|
import kernel.net.Routing;
|
||||||
import haxe.ds.ReadOnlyArray;
|
import haxe.ds.ReadOnlyArray;
|
||||||
import lib.cli.TermHandle;
|
|
||||||
import lib.cli.CLIApp;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class Net extends CLIApp {
|
class Net implements Process {
|
||||||
private var handle:TermHandle;
|
private var handle:ProcessHandle;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function invoke(handle:TermHandle):Future<Bool> {
|
public function run(handle:ProcessHandle):Void {
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
|
||||||
var subcommand = handle.args[0];
|
var subcommand = handle.args[0];
|
||||||
@@ -21,86 +21,82 @@ class Net extends CLIApp {
|
|||||||
|
|
||||||
switch (subcommand) {
|
switch (subcommand) {
|
||||||
case "route":
|
case "route":
|
||||||
return Future.sync(route(subcommand_args));
|
route(subcommand_args);
|
||||||
|
return handle.close();
|
||||||
case "iface":
|
case "iface":
|
||||||
return Future.sync(iface(subcommand_args));
|
iface(subcommand_args);
|
||||||
|
return handle.close();
|
||||||
case "help":
|
case "help":
|
||||||
printHelp();
|
printHelp();
|
||||||
return Future.sync(true);
|
return handle.close();
|
||||||
case "ping":
|
case "ping":
|
||||||
return ping(subcommand_args);
|
ping(subcommand_args);
|
||||||
|
// Closes itself
|
||||||
case "proto":
|
case "proto":
|
||||||
return Future.sync(protos());
|
protos();
|
||||||
|
return handle.close();
|
||||||
default:
|
default:
|
||||||
handle.writeLn("Unknown subcommand: " + subcommand);
|
handle.write("Unknown subcommand: " + subcommand);
|
||||||
printHelp();
|
printHelp();
|
||||||
return Future.sync(false);
|
return handle.close(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function printHelp() {
|
private function printHelp() {
|
||||||
handle.writeLn("net route");
|
handle.write("net route");
|
||||||
handle.writeLn("net iface");
|
handle.write("net iface");
|
||||||
handle.writeLn("net help");
|
handle.write("net help");
|
||||||
handle.writeLn("net proto");
|
handle.write("net proto");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function route(args:ReadOnlyArray<String>):Bool {
|
private function route(args:ReadOnlyArray<String>):Void {
|
||||||
var routes = Routing.instance.getRouteTable();
|
var routes = Routing.instance.getRouteTable();
|
||||||
|
|
||||||
for(k => v in routes) {
|
for(k => v in routes) {
|
||||||
handle.writeLn('${k} => ${v.interf.name()}(${v.cost})');
|
handle.write('${k} => ${v.interf.name()}(${v.cost})');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function iface(args:ReadOnlyArray<String>):Bool {
|
private function iface(args:ReadOnlyArray<String>):Bool {
|
||||||
var modems = Peripheral.instance.getModems();
|
var modems = Peripheral.instance.getModems();
|
||||||
|
|
||||||
for (modem in modems) {
|
for (modem in modems) {
|
||||||
handle.writeLn(modem.name());
|
handle.write(modem.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ping(args:ReadOnlyArray<String>): Future<Bool> {
|
function ping(args:ReadOnlyArray<String>): Void {
|
||||||
return new Future<Bool>(trigger -> {
|
|
||||||
if (args.length != 1) {
|
if (args.length != 1) {
|
||||||
handle.writeLn("Usage: net ping id");
|
handle.write("Usage: net ping id");
|
||||||
trigger(false);
|
return handle.close(false);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var toID:Null<Int> = Std.parseInt(args[0]);
|
var toID:Null<Int> = Std.parseInt(args[0]);
|
||||||
|
|
||||||
if (toID == null) {
|
if (toID == null) {
|
||||||
handle.writeLn("Invalid ID");
|
handle.write("Invalid ID");
|
||||||
trigger(false);
|
return handle.close(false);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel.net.Net.instance.ping(toID).handle(result -> {
|
kernel.net.Net.instance.ping(toID).handle(result -> {
|
||||||
switch (result){
|
switch (result){
|
||||||
case Success(_):
|
case Success(_):
|
||||||
handle.writeLn("Ping succeeded");
|
handle.write("Ping succeeded");
|
||||||
trigger(true);
|
return handle.close();
|
||||||
case Failure(failure):
|
case Failure(failure):
|
||||||
handle.writeLn("Ping failed: " + failure);
|
handle.write("Ping failed: " + failure);
|
||||||
trigger(false);
|
return handle.close(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function protos():Bool {
|
function protos():Void {
|
||||||
var protos = kernel.net.Net.instance.getActiveProtocols();
|
var protos = kernel.net.Net.instance.getActiveProtocols();
|
||||||
|
|
||||||
for (proto in protos) {
|
for (proto in protos) {
|
||||||
handle.writeLn(proto);
|
handle.write(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
import kernel.ps.Process;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
import kernel.peripherals.Side;
|
import kernel.peripherals.Side;
|
||||||
import lib.cli.TermHandle;
|
|
||||||
import lib.cli.CLIApp;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class Redstone extends CLIApp {
|
class Redstone implements Process {
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function invoke(handle:TermHandle):Future<Bool> {
|
public function run(handle: ProcessHandle):Void {
|
||||||
var subcommand = handle.args[0];
|
var subcommand = handle.args[0];
|
||||||
|
|
||||||
if (subcommand == null) {
|
if (subcommand == null) {
|
||||||
handle.writeLn("Usage: redstone <on|off|get> <side>");
|
handle.write("Usage: redstone <on|off|get> <side>");
|
||||||
return Future.sync(false);
|
return handle.close(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var side:Null<Side> = handle.args[1];
|
var side:Null<Side> = handle.args[1];
|
||||||
if (side == null) {
|
if (side == null) {
|
||||||
handle.writeLn("Invalid side");
|
handle.write("Invalid side");
|
||||||
return Future.sync(false);
|
return handle.close(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (subcommand) {
|
switch (subcommand) {
|
||||||
@@ -31,14 +31,14 @@ class Redstone extends CLIApp {
|
|||||||
Peripheral.instance.getRedstone(side).setOutput(false);
|
Peripheral.instance.getRedstone(side).setOutput(false);
|
||||||
case "get":
|
case "get":
|
||||||
var value = Peripheral.instance.getRedstone(side).getAnalogInput();
|
var value = Peripheral.instance.getRedstone(side).getAnalogInput();
|
||||||
handle.writeLn("Analog input: " + value);
|
handle.write("Analog input: " + value);
|
||||||
case "help":
|
case "help":
|
||||||
handle.writeLn("Usage: redstone <on|off|get> <side>");
|
handle.write("Usage: redstone <on|off|get> <side>");
|
||||||
default:
|
default:
|
||||||
handle.writeLn("Invalid subcommand");
|
handle.write("Invalid subcommand");
|
||||||
return Future.sync(false);
|
return handle.close(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Future.sync(true);
|
return handle.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,56 @@
|
|||||||
package bin;
|
package bin;
|
||||||
|
|
||||||
import lib.ui.UIApp;
|
import kernel.ps.ProcessHandle;
|
||||||
import lib.cli.TermHandle;
|
import kernel.ps.Process;
|
||||||
import lib.cli.CLIApp;
|
import kernel.ps.ProcessManager;
|
||||||
import lib.Color;
|
import lib.Color;
|
||||||
import kernel.ui.WindowContext;
|
import kernel.ui.WindowContext;
|
||||||
import kernel.ui.WindowManager;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
class Terminal extends UIApp {
|
class Terminal implements Process {
|
||||||
private var context:WindowContext;
|
private var context:WindowContext;
|
||||||
private var input:String = "";
|
private var input:String = "";
|
||||||
private var backlog:Array<String> = [];
|
private var backlog:Array<String> = [];
|
||||||
private var exitTrigger: Bool -> Void;
|
private var handle:ProcessHandle;
|
||||||
|
private var requestRender: () -> Void;
|
||||||
|
|
||||||
public function new() {}
|
public function new() {}
|
||||||
|
|
||||||
public function invoke(context: WindowContext): Future<Bool> {
|
public function run(handle: ProcessHandle): Void {
|
||||||
this.context = context;
|
this.handle = handle;
|
||||||
|
|
||||||
|
var statelessContext = handle.createStatelessWindowContext();
|
||||||
|
|
||||||
|
this.context = statelessContext.ctx;
|
||||||
|
this.requestRender = statelessContext.requestRender;
|
||||||
|
|
||||||
|
statelessContext.setRenderFunc(this.render);
|
||||||
|
|
||||||
this.context.onChar.handle(char -> {
|
this.context.onChar.handle(char -> {
|
||||||
this.input += char;
|
this.input += char;
|
||||||
this.redrawInput();
|
this.requestRender();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.context.onKey.handle(e -> {
|
this.context.onKey.handle(e -> {
|
||||||
if (e.keyCode == 259) {
|
if (e.keyCode == 259) { // Backspace
|
||||||
this.input = this.input.substr(0, this.input.length - 1);
|
this.input = this.input.substr(0, this.input.length - 1);
|
||||||
this.redrawInput();
|
this.requestRender();
|
||||||
} else if (e.keyCode == 257) {
|
} else if (e.keyCode == 257) { // Enter
|
||||||
this.backlog.push("> " + this.input);
|
this.backlog.push("> " + this.input);
|
||||||
var command = this.input;
|
var command = this.input;
|
||||||
this.input = "";
|
this.input = "";
|
||||||
this.redrawBacklog();
|
this.requestRender();
|
||||||
this.redrawInput();
|
|
||||||
this.invokeCommand(command);
|
this.invokeCommand(command);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowManager.instance.focusContextToOutput(context, "main");
|
this.requestRender();
|
||||||
this.redrawInput();
|
}
|
||||||
|
|
||||||
return new Future<Bool>(cb -> {
|
private function render() {
|
||||||
this.exitTrigger = cb;
|
redrawBacklog();
|
||||||
return null;
|
redrawInput();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function redrawBacklog() {
|
private function redrawBacklog() {
|
||||||
@@ -99,39 +104,35 @@ class Terminal extends UIApp {
|
|||||||
|
|
||||||
var commandArgs:Array<String> = args.slice(1);
|
var commandArgs:Array<String> = args.slice(1);
|
||||||
var hadInput = false;
|
var hadInput = false;
|
||||||
var handle = new TermHandle(commandArgs, {
|
|
||||||
|
var ps = getProgByName(commandName);
|
||||||
|
if (ps == null) {
|
||||||
|
this.backlog.push("Unknown command: " + commandName);
|
||||||
|
this.redrawBacklog();
|
||||||
|
this.redrawInput();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessManager.run(ps,{
|
||||||
|
args: commandArgs,
|
||||||
onWrite: (s:String) -> {
|
onWrite: (s:String) -> {
|
||||||
if (!hadInput) {
|
if (!hadInput) {
|
||||||
this.backlog.push("");
|
this.backlog.push("");
|
||||||
hadInput = true;
|
hadInput = true;
|
||||||
}
|
}
|
||||||
this.backlog[this.backlog.length - 1] += s;
|
this.backlog[this.backlog.length - 1] += s;
|
||||||
this.redrawBacklog();
|
this.requestRender();
|
||||||
},
|
},
|
||||||
onNewLine: () -> {
|
onExit: (success:Bool) -> {
|
||||||
this.backlog.push("");
|
|
||||||
this.redrawBacklog();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var prog:CLIApp = getProgByName(commandName);
|
|
||||||
|
|
||||||
if (prog == null) {
|
|
||||||
this.backlog.push("Command not found: " + commandName);
|
|
||||||
this.redrawBacklog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.context.setCursorBlink(false);
|
|
||||||
|
|
||||||
prog.invoke(handle).handle((exitCode) -> {
|
|
||||||
// Cleanup extra newline
|
|
||||||
if (this.backlog[this.backlog.length - 1] == "") {
|
if (this.backlog[this.backlog.length - 1] == "") {
|
||||||
this.backlog.pop();
|
this.backlog.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.redrawInput();
|
this.requestRender();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.context.setCursorBlink(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseArgs(command:String):Array<String> {
|
private function parseArgs(command:String):Array<String> {
|
||||||
@@ -144,7 +145,7 @@ class Terminal extends UIApp {
|
|||||||
this.redrawBacklog();
|
this.redrawBacklog();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getProgByName(name:String):CLIApp {
|
private function getProgByName(name:String):Process {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "hello":
|
case "hello":
|
||||||
return new HelloWorld();
|
return new HelloWorld();
|
||||||
@@ -156,6 +157,8 @@ class Terminal extends UIApp {
|
|||||||
return new Disk();
|
return new Disk();
|
||||||
case "gps":
|
case "gps":
|
||||||
return new GPS();
|
return new GPS();
|
||||||
|
case "turtle":
|
||||||
|
return new Turtle();
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/bin/Turtle.hx
Normal file
44
src/bin/Turtle.hx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package bin;
|
||||||
|
|
||||||
|
import lib.CLIAppBase;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
class Turtle extends CLIAppBase {
|
||||||
|
public function new() {
|
||||||
|
registerSyncSubcommand("forward", (args)->{
|
||||||
|
return perform(kernel.turtle.Turtle.instance.forward());
|
||||||
|
});
|
||||||
|
|
||||||
|
registerSyncSubcommand("back", (args)->{
|
||||||
|
return perform(kernel.turtle.Turtle.instance.back());
|
||||||
|
});
|
||||||
|
|
||||||
|
registerSyncSubcommand("left", (args)->{
|
||||||
|
return perform(kernel.turtle.Turtle.instance.turnLeft());
|
||||||
|
});
|
||||||
|
|
||||||
|
registerSyncSubcommand("right", (args)->{
|
||||||
|
return perform(kernel.turtle.Turtle.instance.turnRight());
|
||||||
|
});
|
||||||
|
|
||||||
|
registerSyncSubcommand("up", (args)->{
|
||||||
|
return perform(kernel.turtle.Turtle.instance.up());
|
||||||
|
});
|
||||||
|
|
||||||
|
registerSyncSubcommand("down", (args)->{
|
||||||
|
return perform(kernel.turtle.Turtle.instance.down());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function perform(outcome: Outcome<Noise,String>): Bool {
|
||||||
|
switch outcome {
|
||||||
|
case Success(_):
|
||||||
|
return true;
|
||||||
|
case Failure(error):
|
||||||
|
handle.write(error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package kernel;
|
package kernel;
|
||||||
|
|
||||||
|
import kernel.gps.INS;
|
||||||
import kernel.fs.FS;
|
import kernel.fs.FS;
|
||||||
import kernel.gps.GPS;
|
import kernel.gps.GPS;
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
@@ -34,6 +35,7 @@ class Init {
|
|||||||
Net.instance = new Net();
|
Net.instance = new Net();
|
||||||
|
|
||||||
GPS.instance = new GPS();
|
GPS.instance = new GPS();
|
||||||
|
INS.instance = new INS();
|
||||||
|
|
||||||
// Register default terminate handler
|
// Register default terminate handler
|
||||||
KernelEvents.instance.onTerminate.handle(_->{
|
KernelEvents.instance.onTerminate.handle(_->{
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ class GPS {
|
|||||||
private var cachedPosition:Pos3;
|
private var cachedPosition:Pos3;
|
||||||
private var lastPositionResponse: Array<{pos:Pos3,dist:Float}> = [];
|
private var lastPositionResponse: Array<{pos:Pos3,dist:Float}> = [];
|
||||||
|
|
||||||
|
private var futureResolve: (pos:Null<Pos3>) -> Void = null;
|
||||||
|
|
||||||
@:allow(kernel.Init)
|
@:allow(kernel.Init)
|
||||||
private function new() {
|
private function new() {
|
||||||
this.loadCachedPosition();
|
this.loadCachedPosition();
|
||||||
@@ -39,6 +41,12 @@ class GPS {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.gps.INS)
|
||||||
|
private function setINSPosition(pos:Pos3) {
|
||||||
|
cachedPosition = pos;
|
||||||
|
posAccuracy = 1;
|
||||||
|
}
|
||||||
|
|
||||||
public function getPosition():Null<Pos3> {
|
public function getPosition():Null<Pos3> {
|
||||||
return cachedPosition;
|
return cachedPosition;
|
||||||
}
|
}
|
||||||
@@ -52,8 +60,18 @@ class GPS {
|
|||||||
posAccuracy = 0;
|
posAccuracy = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function locate() {
|
public function locate():Future<Null<Pos3>> {
|
||||||
|
// TODO: implenet a timeout
|
||||||
|
// TODO: dont send a request twice if the last one is still pending or we moved
|
||||||
|
return new Future<Null<Pos3>>((resolve)->{
|
||||||
|
this.futureResolve = resolve;
|
||||||
sendPositionRequest();
|
sendPositionRequest();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveFuture(pos:Null<Pos3>) {
|
||||||
|
this.futureResolve(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function persistCachedPositon() {
|
private function persistCachedPositon() {
|
||||||
@@ -124,13 +142,19 @@ class GPS {
|
|||||||
|
|
||||||
if (lastPositionResponse.length < 4) return; // We need at least 3 responses to calculate the position
|
if (lastPositionResponse.length < 4) return; // We need at least 3 responses to calculate the position
|
||||||
|
|
||||||
var calculatedPosition = calculatePosition().round();
|
var calculatedPosition = calculatePosition();
|
||||||
|
|
||||||
|
if (calculatedPosition != null){
|
||||||
|
calculatedPosition = calculatedPosition.round();
|
||||||
|
}
|
||||||
|
|
||||||
lastPositionResponse = []; // Reset the response array
|
lastPositionResponse = []; // Reset the response array
|
||||||
|
|
||||||
if (calculatedPosition == null) return;
|
if (calculatedPosition == null) return;
|
||||||
cachedPosition = calculatedPosition;
|
cachedPosition = calculatedPosition;
|
||||||
posAccuracy = 3;
|
posAccuracy = 3;
|
||||||
|
|
||||||
|
resolveFuture(calculatedPosition);
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
211
src/kernel/gps/INS.hx
Normal file
211
src/kernel/gps/INS.hx
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
package kernel.gps;
|
||||||
|
|
||||||
|
import kernel.log.Log;
|
||||||
|
import kernel.turtle.Turtle;
|
||||||
|
import lib.Pos3;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
class INS {
|
||||||
|
public static var instance:INS;
|
||||||
|
|
||||||
|
private var heading: Null<Pos3> = null;
|
||||||
|
private var alingment: Int = 1; // 0 = degraded, 1 = not aligned, 2 = aligned
|
||||||
|
|
||||||
|
@:allow(kernel.Init)
|
||||||
|
private function new() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.turtle.Turtle)
|
||||||
|
private function moveForward() {
|
||||||
|
if (heading == null) {
|
||||||
|
this.alingment = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
move(heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.turtle.Turtle)
|
||||||
|
private function moveBackward() {
|
||||||
|
if (heading == null) {
|
||||||
|
this.alingment = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
move(heading.negate());
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.turtle.Turtle)
|
||||||
|
private function moveUp() {
|
||||||
|
move({x: 0, y: 1, z: 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.turtle.Turtle)
|
||||||
|
private function moveDown() {
|
||||||
|
move({x: 0, y: -1, z: 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.turtle.Turtle)
|
||||||
|
private function turnLeft() {
|
||||||
|
if (heading == null) return;
|
||||||
|
if (heading.x == 0 && heading.z == -1) {
|
||||||
|
heading = {x: -1, y: 0, z: 0};
|
||||||
|
} else if (heading.x == -1 && heading.z == 0) {
|
||||||
|
heading = {x: 0, y: 0, z: 1};
|
||||||
|
} else if (heading.x == 0 && heading.z == 1) {
|
||||||
|
heading = {x: 1, y: 0, z: 0};
|
||||||
|
} else if (heading.x == 1 && heading.z == 0) {
|
||||||
|
heading = {x: 0, y: 0, z: -1};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.turtle.Turtle)
|
||||||
|
private function turnRight() {
|
||||||
|
if (heading == null) return;
|
||||||
|
if (heading.x == 0 && heading.z == -1) {
|
||||||
|
heading = {x: 1, y: 0, z: 0};
|
||||||
|
} else if (heading.x == -1 && heading.z == 0) {
|
||||||
|
heading = {x: 0, y: 0, z: -1};
|
||||||
|
} else if (heading.x == 0 && heading.z == 1) {
|
||||||
|
heading = {x: -1, y: 0, z: 0};
|
||||||
|
} else if (heading.x == 1 && heading.z == 0) {
|
||||||
|
heading = {x: 0, y: 0, z: 1};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function move(dir: Null<Pos3>) {
|
||||||
|
Log.debug('INS move: $dir');
|
||||||
|
var pos = GPS.instance.getPosition();
|
||||||
|
var newPos = pos + dir;
|
||||||
|
GPS.instance.setINSPosition(newPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeading():Null<Pos3> {
|
||||||
|
return heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function align(): Promise<Noise> {
|
||||||
|
Log.info("Aligning INS");
|
||||||
|
return new Promise<Noise>((resolve,reject)->{
|
||||||
|
|
||||||
|
if (Turtle.instance.getFuelLevel() < 2){
|
||||||
|
Log.warn("Not enough fuel to align");
|
||||||
|
reject(new Error("Not enough fuel to align"));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPS.instance.locate().handle((pos1)->{
|
||||||
|
Log.debug('pos1: $pos1');
|
||||||
|
if (pos1 == null) {
|
||||||
|
Log.warn("GPS not available for 1st position");
|
||||||
|
reject(new Error("GPS not available"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var moved = tryMoving();
|
||||||
|
|
||||||
|
if (moved == -1) {
|
||||||
|
Log.warn("Can't move");
|
||||||
|
reject(new Error("Can't move"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPS.instance.locate().handle((pos2)->{
|
||||||
|
Log.debug('pos2: $pos2');
|
||||||
|
if (pos2 == null) {
|
||||||
|
Log.warn("GPS not available for 2nd position");
|
||||||
|
reject(new Error("GPS not available for 2nd position"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var heading = calcHeading(pos1,pos2,moved);
|
||||||
|
if (heading == null) {
|
||||||
|
Log.error("Can't calculate heading");
|
||||||
|
reject(new Error("Can't calculate heading"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.heading = heading;
|
||||||
|
moveBack(moved);
|
||||||
|
GPS.instance.setINSPosition(pos1);
|
||||||
|
|
||||||
|
resolve(Noise);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// -1 = not moved, 0 = back, 1 = forward, 2 = left, 3 = right
|
||||||
|
private function tryMoving():Int {
|
||||||
|
if (Turtle.instance.back().isSuccess()) {
|
||||||
|
return 0;
|
||||||
|
} else if (Turtle.instance.forward().isSuccess()) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
Turtle.instance.turnLeft(); // TODO: Check if successfull
|
||||||
|
if (Turtle.instance.forward().isSuccess()){
|
||||||
|
return 2;
|
||||||
|
} else if (Turtle.instance.back().isSuccess()) {
|
||||||
|
return 3;
|
||||||
|
} else {
|
||||||
|
// Can't move
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function calcHeading(pos1: Pos3,pos2:Pos3,moved:Int): Null<Pos3> {
|
||||||
|
if (moved == 0) {
|
||||||
|
return pos1 - pos2;
|
||||||
|
} else if (moved == 1) {
|
||||||
|
return pos2 - pos1;
|
||||||
|
} else if (moved == 2) {
|
||||||
|
return rotatePos3ToRight(pos2 - pos1);
|
||||||
|
} else if (moved == 3) {
|
||||||
|
return rotatePos3ToLeft(pos2 - pos1);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function moveBack(moved:Int) {
|
||||||
|
if (moved == 0) {
|
||||||
|
Turtle.instance.forward();
|
||||||
|
// cc.Turtle.forward();
|
||||||
|
} else if (moved == 1) {
|
||||||
|
Turtle.instance.back();
|
||||||
|
// cc.Turtle.back();
|
||||||
|
} else if (moved == 2) {
|
||||||
|
Turtle.instance.back();
|
||||||
|
// cc.Turtle.back();
|
||||||
|
Turtle.instance.turnRight();
|
||||||
|
// cc.Turtle.turnRight();
|
||||||
|
} else if (moved == 3) {
|
||||||
|
Turtle.instance.forward();
|
||||||
|
// cc.Turtle.forward();
|
||||||
|
Turtle.instance.turnRight();
|
||||||
|
// cc.Turtle.turnRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function rotatePos3ToRight(pos:Pos3):Pos3 {
|
||||||
|
if (pos.x == 0 && pos.z == -1) {
|
||||||
|
return {x: 1, y: 0, z: 0};
|
||||||
|
} else if (pos.x == -1 && pos.z == 0) {
|
||||||
|
return {x: 0, y: 0, z: -1};
|
||||||
|
} else if (pos.x == 0 && pos.z == 1) {
|
||||||
|
return {x: -1, y: 0, z: 0};
|
||||||
|
} else if (pos.x == 1 && pos.z == 0) {
|
||||||
|
return {x: 0, y: 0, z: 1};
|
||||||
|
} else {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function rotatePos3ToLeft(pos3:Pos3):Pos3 {
|
||||||
|
return rotatePos3ToRight(rotatePos3ToRight(rotatePos3ToRight(pos3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
8
src/kernel/ps/Process.hx
Normal file
8
src/kernel/ps/Process.hx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package kernel.ps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Defines an independent process that can be run by the kernel.
|
||||||
|
**/
|
||||||
|
interface Process {
|
||||||
|
public function run(handle: ProcessHandle): Void;
|
||||||
|
}
|
||||||
82
src/kernel/ps/ProcessHandle.hx
Normal file
82
src/kernel/ps/ProcessHandle.hx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package kernel.ps;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessManager.PID;
|
||||||
|
import kernel.ui.WindowContext;
|
||||||
|
import kernel.ui.WindowManager;
|
||||||
|
import haxe.ds.ReadOnlyArray;
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
typedef HandleConfig = {
|
||||||
|
?args: Array<String>,
|
||||||
|
?onWrite: Callback<String>,
|
||||||
|
?onExit: Callback<Bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProcessHandle {
|
||||||
|
public var args(get,null): ReadOnlyArray<String>;
|
||||||
|
|
||||||
|
private final pid: PID;
|
||||||
|
private final config:HandleConfig;
|
||||||
|
private final closeFuture: Future<Bool>;
|
||||||
|
private var closeFutureResolev: Bool -> Void;
|
||||||
|
private final windowContexts: Array<WindowContext> = [];
|
||||||
|
|
||||||
|
@:allow(kernel.ps.ProcessManager)
|
||||||
|
private function new(config: HandleConfig,pid: PID) {
|
||||||
|
this.config = config;
|
||||||
|
this.pid = pid;
|
||||||
|
|
||||||
|
this.closeFuture = new Future<Bool>((trigger)->{
|
||||||
|
this.closeFutureResolev = trigger;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.config.onExit != null) {
|
||||||
|
this.closeFuture.handle(this.config.onExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.closeFuture.eager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onExit(): Future<Bool> {
|
||||||
|
return this.closeFuture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close(success: Bool = true): Void {
|
||||||
|
this.dispose();
|
||||||
|
this.closeFutureResolev(success);
|
||||||
|
ProcessManager.removeProcess(this.pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(message: String): Void {
|
||||||
|
this.config.onWrite.invoke(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function writeLine(message: String): Void {
|
||||||
|
this.write(message + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createBufferdWindowContext(): WindowContext {
|
||||||
|
var ctx = WindowManager.instance.createNewContext();
|
||||||
|
this.windowContexts.push(ctx);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createStatelessWindowContext(): {ctx:WindowContext, setRenderFunc: (() -> Void) -> Void, requestRender:() -> Void} {
|
||||||
|
var ctx = WindowManager.instance.createNewStatelessContext();
|
||||||
|
this.windowContexts.push(ctx.ctx);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWindowContexts(): ReadOnlyArray<WindowContext> {
|
||||||
|
return this.windowContexts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function dispose() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_args():ReadOnlyArray<String> {
|
||||||
|
return this.config.args;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/kernel/ps/ProcessManager.hx
Normal file
37
src/kernel/ps/ProcessManager.hx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package kernel.ps;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessHandle.HandleConfig;
|
||||||
|
|
||||||
|
typedef PID = Int;
|
||||||
|
|
||||||
|
class ProcessManager {
|
||||||
|
private static final processList = new Map<PID,ProcessHandle>();
|
||||||
|
|
||||||
|
public static function run(process:Process, config: HandleConfig):PID {
|
||||||
|
var pid = createPID();
|
||||||
|
var handle = new ProcessHandle(config, pid);
|
||||||
|
|
||||||
|
processList.set(pid, handle);
|
||||||
|
|
||||||
|
process.run(handle);
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function createPID(): PID {
|
||||||
|
// TODO: better PID generation
|
||||||
|
|
||||||
|
// generate a random PID
|
||||||
|
return Math.ceil(Math.random() * 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.ui.WindowManager)
|
||||||
|
private static function getProcess(pid:PID):Null<ProcessHandle>{
|
||||||
|
return processList.get(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(kernel.ps.ProcessHandle)
|
||||||
|
private static function removeProcess(pid:PID):Void {
|
||||||
|
processList.remove(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package kernel.turtle;
|
|||||||
|
|
||||||
import kernel.log.Log;
|
import kernel.log.Log;
|
||||||
import kernel.turtle.Types;
|
import kernel.turtle.Types;
|
||||||
|
import kernel.gps.INS;
|
||||||
|
|
||||||
using tink.CoreApi;
|
using tink.CoreApi;
|
||||||
|
|
||||||
@@ -34,32 +35,44 @@ class Turtle {
|
|||||||
|
|
||||||
public function forward():Outcome<Noise, String> {
|
public function forward():Outcome<Noise, String> {
|
||||||
var r = cc.Turtle.forward();
|
var r = cc.Turtle.forward();
|
||||||
return conterToOutcome(r);
|
var r2 = conterToOutcome(r);
|
||||||
|
if (r2.isSuccess()) INS.instance.moveForward();
|
||||||
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function back():Outcome<Noise, String> {
|
public function back():Outcome<Noise, String> {
|
||||||
var r = cc.Turtle.back();
|
var r = cc.Turtle.back();
|
||||||
return conterToOutcome(r);
|
var r2 = conterToOutcome(r);
|
||||||
|
if (r2.isSuccess()) INS.instance.moveBackward();
|
||||||
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function up():Outcome<Noise, String> {
|
public function up():Outcome<Noise, String> {
|
||||||
var r = cc.Turtle.up();
|
var r = cc.Turtle.up();
|
||||||
return conterToOutcome(r);
|
var r2 = conterToOutcome(r);
|
||||||
|
if (r2.isSuccess()) INS.instance.moveUp();
|
||||||
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function down():Outcome<Noise, String> {
|
public function down():Outcome<Noise, String> {
|
||||||
var r = cc.Turtle.down();
|
var r = cc.Turtle.down();
|
||||||
return conterToOutcome(r);
|
var r2 = conterToOutcome(r);
|
||||||
|
if (r2.isSuccess()) INS.instance.moveDown();
|
||||||
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function turnLeft():Outcome<Noise, String> {
|
public function turnLeft():Outcome<Noise, String> {
|
||||||
var r = cc.Turtle.turnLeft();
|
var r = cc.Turtle.turnLeft();
|
||||||
return conterToOutcome(r);
|
var r2 = conterToOutcome(r);
|
||||||
|
if (r2.isSuccess()) INS.instance.turnRight();
|
||||||
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function turnRight():Outcome<Noise, String> {
|
public function turnRight():Outcome<Noise, String> {
|
||||||
var r = cc.Turtle.turnRight();
|
var r = cc.Turtle.turnRight();
|
||||||
return conterToOutcome(r);
|
var r2 = conterToOutcome(r);
|
||||||
|
if (r2.isSuccess()) INS.instance.turnRight();
|
||||||
|
return r2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dig(dir:InteractDirections, ?toolSide:ToolSide):Outcome<Noise, String> {
|
public function dig(dir:InteractDirections, ?toolSide:ToolSide):Outcome<Noise, String> {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package kernel.ui;
|
package kernel.ui;
|
||||||
|
|
||||||
|
import kernel.ps.ProcessManager;
|
||||||
|
import kernel.ps.ProcessManager.PID;
|
||||||
import haxe.ds.ReadOnlyArray;
|
import haxe.ds.ReadOnlyArray;
|
||||||
import kernel.ui.TermWriteable;
|
import kernel.ui.TermWriteable;
|
||||||
import kernel.peripherals.Peripherals.Peripheral;
|
import kernel.peripherals.Peripherals.Peripheral;
|
||||||
@@ -162,4 +164,13 @@ class WindowManager {
|
|||||||
context.setTarget(target);
|
context.setTarget(target);
|
||||||
context.enable();
|
context.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getContextByPID(pid: PID): ReadOnlyArray<WindowContext> {
|
||||||
|
var handle = ProcessManager.getProcess(pid);
|
||||||
|
if (handle == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle.getWindowContexts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/lib/CLIAppBase.hx
Normal file
58
src/lib/CLIAppBase.hx
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package lib;
|
||||||
|
|
||||||
|
import kernel.ps.Process;
|
||||||
|
import kernel.ps.ProcessHandle;
|
||||||
|
|
||||||
|
using tink.CoreApi;
|
||||||
|
|
||||||
|
abstract class CLIAppBase implements Process {
|
||||||
|
private var handle: ProcessHandle;
|
||||||
|
|
||||||
|
private final _subcommandsSync: Map<String, (Array<String>) -> Bool> = [];
|
||||||
|
private final _subcommandsAsync: Map<String, (Array<String>) -> Future<Bool>> = [];
|
||||||
|
private final _subcommandsSynopsis: Array<String> = [];
|
||||||
|
|
||||||
|
public function run(handle: ProcessHandle){
|
||||||
|
this.handle = handle;
|
||||||
|
|
||||||
|
var subcommand = handle.args[0];
|
||||||
|
|
||||||
|
if (subcommand == null || subcommand == "") {
|
||||||
|
handle.writeLine("No subcommand specified");
|
||||||
|
printHelp();
|
||||||
|
return handle.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var args = handle.args.slice(1);
|
||||||
|
|
||||||
|
if (_subcommandsSync.exists(subcommand)) {
|
||||||
|
var result = _subcommandsSync[subcommand](args);
|
||||||
|
return handle.close(result);
|
||||||
|
} else if (_subcommandsAsync.exists(subcommand)) {
|
||||||
|
_subcommandsAsync[subcommand](args).handle(handle.close);
|
||||||
|
} else {
|
||||||
|
handle.writeLine("Unknown subcommand: " + subcommand);
|
||||||
|
printHelp();
|
||||||
|
return handle.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerSyncSubcommand(command: String, callback: (Array<String>) -> Bool, synopsis: String = null) {
|
||||||
|
_subcommandsSync.set(command, callback);
|
||||||
|
_subcommandsSynopsis.push(command + " " + synopsis);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerAsyncSubcommand(command: String, callback: (Array<String>) -> Future<Bool>, synopsis: String = null) {
|
||||||
|
_subcommandsAsync.set(command, callback);
|
||||||
|
_subcommandsSynopsis.push(command + " " + synopsis);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function printHelp() {
|
||||||
|
handle.writeLine("Usage: <subcommand> [args]");
|
||||||
|
handle.writeLine("Subcommands:");
|
||||||
|
for (subcommand in _subcommandsSynopsis) {
|
||||||
|
handle.writeLine(" " + subcommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package lib;
|
package lib;
|
||||||
|
|
||||||
|
import kernel.ps.Process;
|
||||||
|
import kernel.ps.ProcessManager;
|
||||||
import bin.KernelLog;
|
import bin.KernelLog;
|
||||||
import lib.ui.elements.UIElement;
|
import lib.ui.elements.UIElement;
|
||||||
import lib.ui.elements.TextElement;
|
import lib.ui.elements.TextElement;
|
||||||
@@ -88,33 +90,18 @@ class HomeContext {
|
|||||||
focusContext(contextId);
|
focusContext(contextId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function addTerminal(){
|
private function spawnPs(ps: Process) {
|
||||||
var newContext = WindowManager.instance.createNewBufferedContext();
|
var pid = ProcessManager.run(ps, {});
|
||||||
|
var lastContextID = -1;
|
||||||
|
|
||||||
// Create new terminal
|
for ( ctx in WindowManager.instance.getContextByPID(pid)){
|
||||||
var term = new Terminal();
|
lastContextID = addContextNextWorkspace(ctx);
|
||||||
term.invoke(newContext);
|
}
|
||||||
|
|
||||||
var contextID = addContextNextWorkspace(newContext);
|
if (lastContextID == -1) {
|
||||||
if (contextID == -1) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
focusContext(contextID);
|
focusContext(lastContextID);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function addLog(){
|
|
||||||
var newContext = WindowManager.instance.createNewBufferedContext();
|
|
||||||
|
|
||||||
// Create new terminal
|
|
||||||
var term = new KernelLog();
|
|
||||||
term.invoke(newContext);
|
|
||||||
|
|
||||||
var contextID = addContextNextWorkspace(newContext);
|
|
||||||
if (contextID == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
focusContext(contextID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function render() {
|
private function render() {
|
||||||
@@ -128,8 +115,8 @@ class HomeContext {
|
|||||||
for (i in workspaceIDs) new TextElement('Switch to ${i + 1}', {onClick: this.handleSelectContext.bind(i)})
|
for (i in workspaceIDs) new TextElement('Switch to ${i + 1}', {onClick: this.handleSelectContext.bind(i)})
|
||||||
];
|
];
|
||||||
|
|
||||||
children.push(new TextElement('Add Terminal', {onClick: this.addTerminal}));
|
children.push(new TextElement('Add Terminal', {onClick: this.spawnPs.bind(new Terminal())}));
|
||||||
children.push(new TextElement('Add Log', {onClick: this.addLog}));
|
children.push(new TextElement('Add Log', {onClick: this.spawnPs.bind(new KernelLog())}));
|
||||||
children.push(new TextElement('Exit', {onClick: KernelEvents.instance.shutdown}));
|
children.push(new TextElement('Exit', {onClick: KernelEvents.instance.shutdown}));
|
||||||
|
|
||||||
renderer.setChildren(children);
|
renderer.setChildren(children);
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package lib.cli;
|
|
||||||
|
|
||||||
using tink.CoreApi;
|
|
||||||
|
|
||||||
abstract class CLIApp {
|
|
||||||
public abstract function invoke(handle: TermHandle): Future<Bool>;
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package lib.cli;
|
|
||||||
|
|
||||||
import haxe.ds.ReadOnlyArray;
|
|
||||||
|
|
||||||
typedef TermHandleEvents = {
|
|
||||||
onWrite: String->Void,
|
|
||||||
onNewLine: Void->Void,
|
|
||||||
}
|
|
||||||
|
|
||||||
class TermHandle {
|
|
||||||
public final args:ReadOnlyArray<String>;
|
|
||||||
private final events:TermHandleEvents;
|
|
||||||
|
|
||||||
@:allow(bin.Terminal)
|
|
||||||
private function new(args: Array<String>, events: TermHandleEvents) {
|
|
||||||
this.args = args;
|
|
||||||
this.events = events;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function write(s:String) {
|
|
||||||
this.events.onWrite(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function writeLn(s:String = "") {
|
|
||||||
if (s != "")
|
|
||||||
this.events.onWrite(s);
|
|
||||||
this.events.onNewLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user