package pif.arduino.tools;
import static processing.app.I18n._;
import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import processing.app.BaseNoGui;
import processing.app.Platform;
import processing.app.PreferencesData;
import processing.app.Serial;
import processing.app.debug.TargetBoard;
import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatform;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.ProcessUtils;
public class ArduinoConfig extends BaseNoGui {
private static Logger logger = Logger.getLogger(ArduinoConfig.class);
static public int baudrate = 9600;
static public void setIdePath(String arduinoIdePath) {
System.setProperty("user.dir", arduinoIdePath);
ProcessUtils.pwd = new File(arduinoIdePath);
}
// Arduino IDE path must be fixed before this class is accessed
// It's explicitly passed to init method, even if it was not in command line parameters
static public void initialize(String preferencesFile) {
// caller platform specific initializations
initPlatform();
getPlatform().init();
initPortableFolder();
// if preferencesFile is null, this method uses default location
PreferencesData.init(absoluteFile(preferencesFile));
String sketchbookPath = getSketchbookPath();
// If no path is set, get the default sketchbook folder for this platform
if (sketchbookPath == null) {
if (BaseNoGui.getPortableFolder() != null)
PreferencesData.set("sketchbook.path", getPortableSketchbookFolder());
else
showError(_("No sketchbook"), _("Sketchbook path not defined"), null);
}
// now that sketchbook path is defined, specific hardware specified in it will be found
initPackages();
}
static public void changePathSeparators(PreferencesMap prefs) {
// do something only under windows
if (System.getProperty("os.name").indexOf("Windows") == -1) {
return;
}
for (String key : prefs.keySet()) {
if (key.endsWith(".path")) {
String value = prefs.get(key);
if (value != null) {
prefs.put(key, value.replace('\\', '/'));
}
}
}
}
private static List<TargetBoard> boardList = null;
/**
* return a list of all known target boards
*/
public static List<TargetBoard> listBoards() {
if (boardList == null) {
boardList = new ArrayList<TargetBoard>();
for (Entry<String, TargetPackage> pkgEntry : ArduinoConfig.packages.entrySet()) {
for (Entry<String, TargetPlatform> pfEntry : pkgEntry.getValue().getPlatforms().entrySet()) {
for (Entry<String, TargetBoard> bdEntry : pfEntry.getValue().getBoards().entrySet()) {
boardList.add(bdEntry.getValue());
}
}
}
}
return boardList;
}
/**
* pretty print known target board list
* @param output
* stream into which output is sent
*/
public static void listBoards(PrintStream output, boolean raw, boolean withPidVid) {
if (!raw) {
output.println("Board list (to be specified as a -b argument) :");
}
for (TargetBoard board: listBoards()) {
TargetPlatform pf = board.getContainerPlatform();
TargetPackage pkg = pf.getContainerPackage();
if (raw) {
output.println(String.format("%s:%s:%s",
board.getId(), pf.getId(), pkg.getId()));
} else {
StringBuffer vidPids = new StringBuffer();
if (withPidVid) {
List<String> vids = new LinkedList<String>(board.getPreferences().subTree("vid").values());
if (!vids.isEmpty()) {
List<String> pids = new LinkedList<String>(board.getPreferences().subTree("pid").values());
for (int i = 0; i < vids.size(); i++) {
vidPids.append(" " + vids.get(i) + "/" + pids.get(i));
}
}
}
output.println(String.format(
" %1$s = %2$s (%3$s:%4$s:%1$s)%5$s",
board.getId(), board.getName(), pf.getId(), pkg.getId(), vidPids));
}
}
}
protected static TargetBoard getBoardByName(String name) {
for (TargetBoard b : listBoards()) {
if (b.getName().equals(name)) {
return b;
}
}
return null;
}
private static List<PortBoard> portList = null;
/**
* cc.arduino.packages.BoardPort class contains just a board name instead of
* an associated board structure this class keep the link with board class
*/
public static class PortBoard {
public String address;
public TargetBoard board = null;
PortBoard(String address, String boardName) {
this.address = address;
if (boardName != null) {
board = getBoardByName(boardName);
}
}
}
public static List<PortBoard> listPorts() {
return listPorts(false);
}
public static List<PortBoard> listPorts(boolean rescan) {
if (portList == null || rescan) {
Platform os = BaseNoGui.getPlatform();
String devicesListOutput = os.preListAllCandidateDevices();
portList = new ArrayList<PortBoard>();
List<String> ports = Serial.list();
for (String port : ports) {
String boardName = os.resolveDeviceAttachedTo(port, BaseNoGui.packages, devicesListOutput);
portList.add(new PortBoard(port, boardName));
}
}
return portList;
}
public static void listPorts(PrintStream output, boolean raw) {
listPorts(output, raw, false);
}
public static void listPorts(PrintStream output, boolean raw, boolean rescan) {
if (!raw) {
output.println("Port list (to be specified as a -p argument) :");
}
for (PortBoard port: listPorts(rescan)) {
if (raw) {
output.println(port.address);
} else {
if (port.board == null) {
output.println(String.format(" %s", port.address));
} else {
output.println(String.format(" %s (identified as %s)", port.address, port.board.getName()));
}
}
}
}
public static PortBoard getPortByName(String name) {
for (PortBoard port: listPorts()) {
if (port.address.equalsIgnoreCase(name)) {
return port;
}
}
return null;
}
public static void setPort(PortBoard port) {
ArduinoConfig.selectSerialPort(port.address);
}
private static final String USE = "use -B option to list existing ones";
public static void setBoard(TargetBoard board) {
ArduinoConfig.selectBoard(board);
onBoardOrPortChange();
String br = getBoardPreferences().get("upload.speed");
if (br != null) {
baudrate = Integer.parseInt(br);
logger.info("Setting baudrate to " + baudrate);
} else {
logger.debug("No default baudrate found");
}
}
public static TargetBoard setBoard(String boardName) {
TargetBoard result = null;
String options = null;
String[] boardComponents = boardName.split(":");
switch (boardComponents.length) {
case 4:
options = boardComponents[3];
// NO BREAK
case 3: {
TargetPackage pkg = ArduinoConfig.packages.get(boardComponents[0]);
if (pkg == null) {
logger.error(String.format("package %s not found, " + USE,
boardComponents[0]));
return null;
}
TargetPlatform pf = pkg.get(boardComponents[1]);
if (pf == null) {
logger.error(String.format(
"platform %2$s not found in package %1$s, " + USE,
boardComponents[0], boardComponents[1]));
return null;
}
result = pf.getBoard(boardComponents[2]);
if (result == null || !result.getId().equals(boardComponents[2])) {
logger.error(String.format(
"board %3$s not found in platform %1$s:%2$s" + USE,
boardComponents[0], boardComponents[1],
boardComponents[2]));
return null;
}
}
break;
case 2:
options = boardComponents[1];
// NO BREAK
case 1:
search: for (Entry<String, TargetPackage> pkgEntry : ArduinoConfig.packages
.entrySet()) {
String pkg = pkgEntry.getKey();
for (Entry<String, TargetPlatform> pfEntry : pkgEntry
.getValue().getPlatforms().entrySet()) {
String platform = pfEntry.getKey();
for (Entry<String, TargetBoard> bdEntry : pfEntry
.getValue().getBoards().entrySet()) {
if (boardName.equals(bdEntry.getKey())) {
logger.debug(String.format(
"found board in package %s platform %s",
pkg, platform));
result = bdEntry.getValue();
break search;
}
}
}
}
if (result == null) {
logger.error("board not found, " + USE);
return null;
}
break;
default:
logger.error("bad board name format (must be [package:platform:]board[:options]");
return null;
}
ArduinoConfig.setBoard(result);
if (options != null) {
setOptions(result, options);
}
return result;
}
protected static void setOptions(TargetBoard board, String optionsString) {
String[] options = optionsString.split(",");
for (String option : options) {
String[] keyValue = option.split("=", 2);
if (keyValue.length != 2) {
logger.error("Invalid option '" + option
+ "', should be of the form \"name=value\"");
}
String key = keyValue[0].trim();
String value = keyValue[1].trim();
if (!board.hasMenu(key)) {
logger.warn(String.format("Invalid option '%s' for board '%s'",
key, board.getId()));
}
if (board.getMenuLabel(key, value) == null) {
logger.warn(String.format(
"Invalid '%s' option value for board '%s'", key,
board.getId()));
}
PreferencesData.set("custom_" + key, board.getId() + "_" + value);
}
}
}