/**
* Copyright (c) 2007, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of MSPSim.
*
* $Id$
*
* -----------------------------------------------------------------
*
* MiscCommands
*
* Author : Joakim Eriksson
* Created : 9 mar 2008
* Updated : $Date$
* $Revision$
*/
package se.sics.mspsim.cli;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.regex.Pattern;
import se.sics.mspsim.chip.RFListener;
import se.sics.mspsim.chip.RFSource;
import se.sics.mspsim.core.Chip;
import se.sics.mspsim.core.MSP430;
import se.sics.mspsim.core.MSP430Constants;
import se.sics.mspsim.core.TimeEvent;
import se.sics.mspsim.util.ComponentRegistry;
import se.sics.mspsim.util.ConfigManager;
import se.sics.mspsim.util.PluginRepository;
import se.sics.mspsim.util.ServiceComponent;
import se.sics.mspsim.util.Utils;
/**
* @author joakim
*
*/
public class MiscCommands implements CommandBundle {
public void setupCommands(final ComponentRegistry registry, CommandHandler handler) {
handler.registerCommand("grep", new BasicLineCommand("print lines matching the specified pattern", "[-i] [-v] <regexp>") {
private PrintStream out;
private Pattern pattern;
private boolean isInverted = false;
public int executeCommand(CommandContext context) {
int index = 0;
int flags = 0;
while (index + 1 < context.getArgumentCount()) {
if ("-i".equals(context.getArgument(index))) {
flags |= Pattern.CASE_INSENSITIVE;
} else if ("-v".equals(context.getArgument(index))) {
isInverted = true;
} else {
context.err.println("unknown option: " + context.getArgument(index));
return 1;
}
index++;
}
out = context.out;
pattern = Pattern.compile(context.getArgument(index), flags);
return 0;
}
public void lineRead(String line) {
boolean isMatch = pattern.matcher(line).find();
if(isMatch ^ isInverted) {
out.println(line);
}
}
});
handler.registerCommand("timestamp", new BasicLineCommand("print lines prefixed with timestamp as milliseconds or CPU cycles", "[-c]") {
private PrintStream out;
private MSP430 cpu;
boolean useCycles;
long startTime;
public int executeCommand(CommandContext context) {
cpu = registry.getComponent(MSP430.class);
if (cpu == null) {
context.err.println("could not access the CPU.");
return 1;
}
out = context.out;
if (context.getArgumentCount() > 0) {
if ("-c".equals(context.getArgument(0))) {
useCycles = true;
} else {
context.err.println("unknown argument: " + context.getArgument(0));
return 1;
}
}
startTime = System.currentTimeMillis() - (long)cpu.getTimeMillis();
return 0;
}
public void lineRead(String line) {
if (useCycles) {
out.println(Long.toString(cpu.cycles) + ' ' + line);
} else {
out.println(Long.toString(startTime + (long)cpu.getTimeMillis()) + ' ' + line);
}
}
});
handler.registerCommand("speed", new BasicCommand("set the speed factor for the CPU", "[factor]") {
public int executeCommand(CommandContext context) {
MSP430 cpu = registry.getComponent(MSP430.class);
if (cpu == null) {
context.err.println("could not access the CPU.");
return 1;
} else if (context.getArgumentCount() == 0) {
/* No speed specified. Simply show current speed. */
} else {
double rate = context.getArgumentAsDouble(0);
if (rate > 0.0) {
cpu.setExecutionRate(rate);
} else {
context.err.println("Speed factor must be larger than zero.");
return 1;
}
}
double rate = cpu.getExecutionRate();
context.out.printf("Speed factor is set to %.2f\n", rate);
return 0;
}
});
handler.registerCommand("echo", new BasicCommand("echo arguments", "") {
public int executeCommand(CommandContext context) {
StringBuilder sb = new StringBuilder();
for (int i = 0, n = context.getArgumentCount(); i < n; i++) {
if (i > 0) sb.append(' ');
sb.append(context.getArgument(i));
}
context.out.println(sb.toString());
return 0;
}
});
handler.registerCommand("source", new BasicCommand("run script", "[-v] <filename>") {
public int executeCommand(CommandContext context) {
boolean verbose = false;
if (context.getArgumentCount() > 1) {
verbose = "-v".equals(context.getArgument(0));
}
File fp = new File(context.getArgument(context.getArgumentCount() - 1));
if (!fp.canRead()) {
context.err.println("could not find the script file '" + context.getArgument(0) + "'.");
return 1;
}
try {
FileInputStream infs = new FileInputStream(fp);
BufferedReader input = new BufferedReader(new InputStreamReader(infs));
try {
String line;
while ((line = input.readLine()) != null) {
if (verbose) context.out.println(line);
context.executeCommand(line);
}
} finally {
input.close();
}
} catch (IOException e) {
e.printStackTrace(context.err);
return 1;
}
return 0;
}
});
handler.registerCommand("repeat", new BasicAsyncCommand("repeat the specified command line", "[-t delay] [-c count] <command line>") {
private MSP430 cpu;
private int period = 1;
private int count = 0;
private int maxCount = -1;
private String commandLine;
private boolean isRunning = true;
public int executeCommand(final CommandContext context) {
int index = 0;
do {
String a = context.getArgument(index);
if (a.startsWith("-")) {
if (a.equals("-t")) {
period = context.getArgumentAsInt(index + 1);
index += 2;
} else if (a.equals("-c")) {
maxCount = context.getArgumentAsInt(index + 1);
index += 2;
} else {
context.err.println("illegal option: " + a);
return 1;
}
} else {
break;
}
} while (true);
if (index + 1 < context.getArgumentCount()) {
context.err.println("too many arguments");
return 1;
}
commandLine = context.getArgument(index);
cpu = registry.getComponent(MSP430.class);
if (cpu == null) {
context.err.println("could not access the CPU.");
return 1;
}
cpu.scheduleTimeEventMillis(new TimeEvent(0) {
@Override
public void execute(long t) {
if (isRunning) {
count++;
context.executeCommand(commandLine);
if ((maxCount <= 0) || (count < maxCount)) {
cpu.scheduleTimeEventMillis(this, period * 1000d);
} else {
stopCommand(context);
}
}
}
}, period * 1000d);
return 0;
}
public void stopCommand(CommandContext context) {
isRunning = false;
context.err.println("[repeat exit: " + commandLine + ']');
context.exit(0);
}
});
handler.registerCommand("exec", new ExecCommand());
handler.registerCommand("trig", new BasicLineCommand("trigg command when getting input", "<command>") {
String command = null;
CommandContext context;
public int executeCommand(CommandContext context) {
StringBuilder sb = new StringBuilder();
for (int i = 0, n = context.getArgumentCount(); i < n; i++) {
if (i > 0) sb.append(' ');
sb.append(context.getArgument(i));
}
command = sb.toString();
this.context = context;
return 0;
}
public void lineRead(String line) {
context.executeCommand(command);
}
});
handler.registerCommand("install", new BasicCommand("install and start a plugin", "ClassName [Name]") {
@Override
public int executeCommand(CommandContext context) {
String className = context.getArgument(0);
String name = className;
if (context.getArgumentCount() > 1) {
name = context.getArgument(1);
}
if (registry.getComponent(name) != null) {
context.err.println("Another component with name '" + name + "' is already installed");
return 1;
}
Class<?> pluginClass = null;
PluginRepository plugins = (PluginRepository) registry.getComponent("pluginRepository");
try {
try {
pluginClass = plugins != null ? plugins.loadClass(className) :
Class.forName(className);
} catch (ClassNotFoundException e) {
String newClassName = "se.sics.mspsim.plugin." + className;
pluginClass = plugins != null ? plugins.loadClass(newClassName) :
Class.forName(newClassName);
}
Object component = pluginClass.newInstance();
registry.registerComponent(name, component);
return 0;
} catch (Exception e1) {
e1.printStackTrace(context.err);
}
return 1;
}
});
handler.registerCommand("service", new BasicCommand("handle service plugins", "[-f] [class name|service name] [start|stop]") {
@Override
public int executeCommand(CommandContext context) {
int index = 0;
boolean verbose = true;
if (context.getArgumentCount() > 0 && "-f".equals(context.getArgument(index))) {
index++;
verbose = false;
}
if (context.getArgumentCount() == index) {
ServiceComponent[] sc = registry.getAllComponents(ServiceComponent.class);
if (sc.length == 0) {
context.out.println("No services found.");
} else {
for (ServiceComponent service : sc) {
context.out.printf(" %-20s %s\n", service.getName(), service.getStatus());
}
}
return 0;
}
String name = context.getArgument(index++);
ServiceComponent sc = getServiceForName(registry, name);
if (sc == null) {
if (verbose) {
context.err.println("could not find service '" + name + "'");
return 1;
}
return 0;
}
if (context.getArgumentCount() == index) {
context.out.printf(" %-20s %s\n", sc.getName(), sc.getStatus());
return 0;
}
String operation = context.getArgument(index);
if ("start".equals(operation)) {
if (sc.getStatus() == ServiceComponent.Status.STARTED) {
context.out.println("service " + sc.getName() + " already started");
} else {
sc.start();
context.out.println("service " + sc.getName() + " started");
}
return 0;
}
if ("stop".equals(operation)) {
if (sc.getStatus() == ServiceComponent.Status.STOPPED) {
context.out.println("service " + sc.getName() + " already stopped");
} else {
sc.stop();
context.out.println("service " + sc.getName() + " stopped");
}
return 0;
}
context.err.println("unknown operation '" + operation + "'");
return 1;
}
});
handler.registerCommand("rflistener", new BasicLineCommand("an rflistener", "<input|output> <rf-chip>") {
CommandContext context;
RFSource source;
RFListener listener;
final MSP430 cpu = registry.getComponent(MSP430.class);
public int executeCommand(CommandContext ctx) {
this.context = ctx;
String inout = context.getArgument(0);
Chip chip = cpu.getChip(context.getArgument(1));
if (chip == null) {
context.err.println("Error: could not find chip '" + context.getArgument(1) + '\'');
return 1;
}
if ("output".equals(inout)) {
if (chip instanceof RFSource) {
source = (RFSource) chip;
listener = new RFListener() {
public void receivedByte(byte data) {
context.out.println(Utils.hex8(data));
}
};
source.addRFListener(listener);
} else {
context.err.println("Error: chip is not an RF source");
return 1;
}
} else if ("input".equals(inout)){
listener = (RFListener) chip;
} else {
context.err.println("Error: illegal type: " + inout);
return 1;
}
return 0;
}
@Override
public void lineRead(String line) {
if (listener != null) {
byte[] data = Utils.hexconv(line);
if (data != null) {
context.out.println("RFListener: to radio: " + line);
for (int i = 0; i < data.length; i++) {
listener.receivedByte(data[i]);
}
} else {
context.out.println("RFListener: " + line);
}
}
}
@Override
public void stopCommand(CommandContext context) {
if (source != null) {
source.removeRFListener(listener);
}
super.stopCommand(context);
}
});
handler.registerCommand("sysinfo", new BasicCommand("show info about the MSPSim system", "[-registry] [-config]") {
public int executeCommand(CommandContext context) {
ConfigManager config = (ConfigManager) registry.getComponent("config");
context.out.println("--------- System info ----------\n");
context.out.println("MSPSim version: " + MSP430Constants.VERSION);
context.out.println("Java version : " + System.getProperty("java.version") + " " +
System.getProperty("java.vendor"));
context.out.println("Firmware : " + config.getProperty("firmwareFile", "-"));
context.out.println("AutoloadScript: " + config.getProperty("autoloadScript", "-"));
context.out.println();
if (context.getOption("registry")) {
context.out.println("--------- Registry info --------\n");
registry.printRegistry(context.out);
}
if (context.getOption("config")) {
context.out.println("--------- Configuration ---------\n");
config.print(context.out);
}
return 0;
}
});
handler.registerCommand("quit", new BasicCommand("exit MSPSim", "") {
public int executeCommand(CommandContext context) {
/* TODO: flush all files, etc.... */
System.exit(0);
return 0;
}
});
handler.registerCommand("exit", new BasicCommand("exit MSPSim", "") {
public int executeCommand(CommandContext context) {
System.exit(0);
return 0;
}
});
handler.registerCommand("set", new BasicCommand("set a config parameter", "<parameter> <value>") {
public int executeCommand(CommandContext context) {
ConfigManager config = (ConfigManager) registry.getComponent("config");
config.setProperty(context.getArgument(0), context.getArgument(1));
context.out.println("set " + context.getArgument(0) + " to " + context.getArgument(1));
return 0;
}
});
}
private static ServiceComponent getServiceForName(ComponentRegistry registry, String name) {
Object o = registry.getComponent(name);
if (o instanceof ServiceComponent) {
return (ServiceComponent) o;
}
return null;
}
}