/******************************************************************************* * Copyright (c) 2008, 2011 Thomas Holland (thomas@innot.de) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Thomas Holland - initial API and implementation *******************************************************************************/ package de.innot.avreclipse.core.targets.tools; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.innot.avreclipse.core.avrdude.AVRDudeException; import de.innot.avreclipse.core.targets.IGDBServerTool; import de.innot.avreclipse.core.targets.IProgrammer; import de.innot.avreclipse.core.targets.IProgrammerTool; import de.innot.avreclipse.core.targets.ITargetConfiguration; import de.innot.avreclipse.core.targets.ITargetConfiguration.Result; import de.innot.avreclipse.core.targets.ITargetConfiguration.ValidationResult; import de.innot.avreclipse.core.toolinfo.ICommandOutputListener; /** * @author Thomas Holland * @since 2.4 * */ public class AvariceTool extends AbstractTool implements IProgrammerTool, IGDBServerTool { public final static String ID = "avreclipse.avarice"; public final static String NAME = "AVaRICE"; public final static String ATTR_CMD_NAME = ID + ".command"; private final static String DEF_CMD_NAME = "avarice"; public final static String ATTR_USE_CONSOLE = ID + ".useconsole"; public final static String DEF_USE_CONSOLE = Boolean.toString(true); // Change to false for release private final static String[] ALL_ATTRS = new String[] { ATTR_CMD_NAME, ATTR_USE_CONSOLE }; private ICommandOutputListener fOutputListener = new AvariceOutputListener(); private Set<String> fProgrammerIds; /** Cache of all Name/Version strings, mapped to their respective command name. */ private Map<String, String> fNameVersionMap = new HashMap<String, String>(); /** Cache of all MCU Sets, mapped to their respective command name */ private Map<String, Set<String>> fMCUMap = new HashMap<String, Set<String>>(); public AvariceTool(ITargetConfiguration hc) { super(hc); // tell the hardware configuration about the avarice attributes and their default values. // String[][] avariceattrs = new String[][] { { ATTR_CMD_NAME, DEF_CMD_NAME }, // { ATTR_USE_CONSOLE, DEF_USE_CONSOLE } }; // getHardwareConfig().addAttributes(this, avariceattrs); } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.ITargetConfigurationTool#getId() */ public String getId() { return ID; } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.ITargetConfigurationTool#getName() */ public String getName() { return NAME; } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.IAttributeProvider#getAttributes() */ public String[] getAttributes() { return Arrays.copyOf(ALL_ATTRS, ALL_ATTRS.length); } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.IAttributeProvider#getDefaultValue(java.lang.String) */ public String getDefaultValue(String attribute) { String defaultvalue = null; if (ATTR_CMD_NAME.equals(attribute)) { defaultvalue = DEF_CMD_NAME; } else if (ATTR_USE_CONSOLE.equals(attribute)) { defaultvalue = DEF_USE_CONSOLE; } return defaultvalue; } /* * (non-Javadoc) * @see * de.innot.avreclipse.core.targets.tools.AbstractTool#getCommand(de.innot.avreclipse.core.targets * .ITargetConfiguration) */ public String getCommand() { String command = getHardwareConfig().getAttribute(ATTR_CMD_NAME); if (command == null || command.length() == 0) { command = DEF_CMD_NAME; } return command; } /* * (non-Javadoc) * @see * de.innot.avreclipse.core.targets.ITargetConfigurationTool#getVersion(de.innot.avreclipse. * core.targets.ITargetConfiguration) */ public String getVersion() throws AVRDudeException { String cmd = getCommand(); // Check if we already have the version in the cache if (fNameVersionMap.containsKey(cmd)) { return fNameVersionMap.get(cmd); } // Execute avarice without any options // The name / version are in the first full line of the output in the format // "AVaRICE version 2.8, Nov 7 2008 22:02:05" String name = null; List<String> stdout = runCommand(""); if (stdout != null) { // look for a line matching "*Version TheVersionNumber *" Pattern mcuPat = Pattern.compile(".*version\\s+([\\w\\.]+).*"); Matcher m; for (String line : stdout) { m = mcuPat.matcher(line); if (!m.matches()) { continue; } name = getName() + " " + m.group(1); break; } } if (name == null) { // could not read the version from the output, probably the regex has a // mistake. Return a reasonable default. return getName() + " ?.?"; } fNameVersionMap.put(cmd, name); return name; } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.tools.AbstractTool#getOutputListener() */ @Override protected ICommandOutputListener getOutputListener() { return fOutputListener; } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.ITargetConfigurationTool#getMCUs() */ public Set<String> getMCUs() throws AVRDudeException { String cmd = getCommand(); if (fMCUMap.containsKey(cmd)) { return fMCUMap.get(cmd); } Set<String> allmcus = new HashSet<String>(); List<String> stdout; stdout = runCommand("--known-devices"); if (stdout != null) { // look for a line matching alphanumeric characters (the mcu id) followed by whitespaces // and "0x" (the beginning of the device id field) Pattern mcuPat = Pattern.compile("(\\w+)\\s+0x.+"); Matcher m; for (String line : stdout) { m = mcuPat.matcher(line); if (!m.matches()) { continue; } allmcus.add(m.group(1)); } } fMCUMap.put(cmd, allmcus); return allmcus; } /* * (non-Javadoc) * @see * de.innot.avreclipse.core.targets.ITargetConfigurationTool#getProgrammers(de.innot.avreclipse * .core.targets.ITargetConfiguration) */ public Set<String> getProgrammers() throws AVRDudeException { if (fProgrammerIds == null) { fProgrammerIds = new HashSet<String>(); for (AvariceProgrammers progger : AvariceProgrammers.values()) { fProgrammerIds.add(progger.getId()); } } return fProgrammerIds; } /* * (non-Javadoc) * @see * de.innot.avreclipse.core.targets.ITargetConfigurationTool#getProgrammer(de.innot.avreclipse * .core.targets.ITargetConfiguration, java.lang.String) */ public IProgrammer getProgrammer(String id) throws AVRDudeException { // Quick check if the programmer id is actually supported by avarice if (!getProgrammers().contains(id)) { return null; } IProgrammer progger = AvariceProgrammers.valueOf(id); return progger; } /* * (non-Javadoc) * @see * de.innot.avreclipse.core.targets.ITargetConfigurationTool#validate(de.innot.avreclipse.core * .targets.ITargetConfiguration, java.lang.String) */ public ValidationResult validate(String attr) { Result result = Result.OK; String description = ""; if (ATTR_CMD_NAME.equals(attr)) { // Check that the command is valid by executing avarice with parameter "--known-devices" and check // that the output is long enough. try { List<String> stdout; stdout = runCommand("--known-devices"); if (stdout.size() < 10) { result = Result.ERROR; description = "Not an AVaRICE executable"; } } catch (AVRDudeException ade) { // avarice not found result = Result.ERROR; description = "Invalid Path"; } } else if (ATTR_USE_CONSOLE.equals(attr)) { // USE_CONSOLE is always valid } else { result = Result.UNKNOWN_ATTRIBUTE; } return new ValidationResult(result, description); } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.IGDBServerTool#isSimulator() */ public boolean isSimulator() { return false; } }