/******************************************************************************* * 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.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.AVRDude; import de.innot.avreclipse.core.toolinfo.ICommandOutputListener; /** * @author Thomas Holland * @since * */ public class AvrdudeTool extends AbstractTool implements IProgrammerTool { public final static String ID = "avreclipse.avrdude"; public final static String NAME = "AVRDude"; private final static AVRDude fAVRDude = AVRDude.getDefault(); public final static String ATTR_CMD_NAME = ID + ".command"; public final static String DEF_CMD_NAME = "avrdude"; public final static String ATTR_USE_CONSOLE = ID + ".useconsole"; public final static String DEF_USE_CONSOLE = Boolean.toString(true); public final static String ATTR_VERBOSITY = ID + ".verbosity"; public final static String DEF_VERBOSITY = Integer.toString(0); private final static String[] ALL_ATTRS = new String[] { ATTR_CMD_NAME, ATTR_USE_CONSOLE, ATTR_VERBOSITY }; private final static String[] VERBOSITY_LEVELS = new String[] { "", "-v", "-vv", "-vvvv" }; /** 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>>(); /** Mapping of mcu id values to their AVRDude format counterparts. */ private Map<String, String> fMCUAVRudeFormatMap = new HashMap<String, String>(); private ICommandOutputListener fOutputListener = new AvrdudeOutputListener(); public AvrdudeTool(ITargetConfiguration hc) { super(hc); // tell the hardware configuration about the avrddue attributes and their default values. // String[][] avariceattrs = new String[][] { { ATTR_CMD_NAME, DEF_CMD_NAME }, // { ATTR_USE_CONSOLE, DEF_USE_CONSOLE }, { ATTR_VERBOSITY, DEF_VERBOSITY } }; // 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; } else if (ATTR_VERBOSITY.equals(attribute)) { defaultvalue = DEF_VERBOSITY; } 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 = DEF_CMD_NAME; } return command; } /* * (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#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 avrdude in verbose mode with a dummy programmer (to silence the warning that // would cause an AVRDudeException by the output listener) // The name / version are in the first full line of the output in the format // "avrdude: Version 5.6cvs, compiled on Nov 10 2008 at 17:15:38" String name = null; List<String> stdout = runCommand("-v"); 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.ITargetConfigurationTool#getMCUs() */ public Set<String> getMCUs() throws AVRDudeException { // Check if we already have the list in the cache String cmd = getCommand(); if (fMCUMap.containsKey(cmd)) { return fMCUMap.get(cmd); } // Execute avrdude with the "-p?" to get a list of all supported mcus. // The parse the all output for lines matching // avrdudeid = mcuid [otherstuff] Set<String> allmcus = new HashSet<String>(); List<String> stdout; stdout = runCommand("-p?"); if (stdout != null) { Pattern mcuPat = Pattern.compile("\\s*(\\w+)\\s*=\\s*(\\w+).*"); Matcher m; for (String line : stdout) { m = mcuPat.matcher(line); if (!m.matches()) { continue; } String avrdudeid = m.group(1); String mcuid = m.group(2).toLowerCase(); fMCUAVRudeFormatMap.put(mcuid, avrdudeid); allmcus.add(mcuid); } } // Save the set in the cache fMCUMap.put(cmd, allmcus); return allmcus; } /* * (non-Javadoc) * @see de.innot.avreclipse.core.targets.ITargetConfigurationTool#getProgrammers() */ public Set<String> getProgrammers() throws AVRDudeException { // FIXME: Change the AVRDude.class API to take the Target configuration into account. return fAVRDude.getProgrammerIDs(); } /* * (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 { // FIXME: Change the AVRDude.class API to take the Target configuration into account. return fAVRDude.getProgrammer(id); } /* * (non-Javadoc) * @see * de.innot.avreclipse.core.targets.ITargetConfigurationTool#validate(de.innot.avreclipse.core * .targets.ITargetConfiguration, java.lang.String) */ public ValidationResult validate(String attr) { if (ATTR_CMD_NAME.equals(attr)) { try { List<String> stdout = runCommand("-?"); for (String line : stdout) { if (line.contains("avrdude")) { return ValidationResult.OK_RESULT; } } } catch (AVRDudeException e) { // Could not execute avrdude with the given command name } return new ValidationResult(Result.ERROR, "Invalid Command for AVRDude"); } else if (ATTR_USE_CONSOLE.equals(attr)) { return ValidationResult.OK_RESULT; } else if (ATTR_VERBOSITY.equals(attr)) { return ValidationResult.OK_RESULT; } else { return new ValidationResult(Result.UNKNOWN_ATTRIBUTE, attr); } } /* * (non-Javadoc) * @see * de.innot.avreclipse.core.targets.tools.AbstractTool#runCommand(de.innot.avreclipse.core.targets * .ITargetConfiguration, java.lang.String[]) */ @Override public List<String> runCommand(String... args) throws AVRDudeException { String[] newargs; String verbosity = getVerbosityArgument(); if (verbosity.length() != 0) { // Not the default verbosity level. Add the verbosity // argument to the array of arguments. newargs = new String[args.length + 1]; newargs[0] = verbosity; System.arraycopy(args, 0, newargs, 1, args.length); } else { newargs = args; } return super.runCommand(newargs); } private String getVerbosityArgument() { int verbosity = getHardwareConfig().getIntegerAttribute(ATTR_VERBOSITY); // little sanity check if (verbosity < 0 || verbosity >= VERBOSITY_LEVELS.length) { verbosity = 2; } return VERBOSITY_LEVELS[verbosity]; } }