public boolean avrdude(Collection params) throws RunnerException {
    List commandDownloader = new ArrayList();
    commandDownloader.add("avrdude");

    // Point avrdude at its config file since it's in a non-standard location.
    if (Base.isMacOS()) {
      commandDownloader.add("-C" + "hardware/tools/avr/etc/avrdude.conf");
    } else if (Base.isWindows()) {
      String userdir = System.getProperty("user.dir") + File.separator;
      commandDownloader.add("-C" + userdir + "hardware/tools/avr/etc/avrdude.conf");
    } else {
      // ???: is it better to have Linux users install avrdude themselves, in
      // a way that it can find its own configuration file?
      commandDownloader.add("-C" + "hardware/tools/avrdude.conf");
    }

    if (Preferences.getBoolean("upload.verbose")) {
      commandDownloader.add("-v");
      commandDownloader.add("-v");
      commandDownloader.add("-v");
      commandDownloader.add("-v");
    } else {
      commandDownloader.add("-q");
      commandDownloader.add("-q");
    }
    // XXX: quick hack to chop the "atmega" off of "atmega8" and "atmega168",
    // then shove an "m" at the beginning.  won't work for attiny's, etc.
    commandDownloader.add(
        "-pm" + Preferences.get("boards." + Preferences.get("board") + ".build.mcu").substring(6));
    commandDownloader.addAll(params);

    return executeUploadCommand(commandDownloader);
  }
  protected boolean burnBootloader(Collection params) throws RunnerException {
    List fuses = new ArrayList();
    fuses.add("-e"); // erase the chip
    fuses.add(
        "-Ulock:w:"
            + Preferences.get("boards." + Preferences.get("board") + ".bootloader.unlock_bits")
            + ":m");
    if (Preferences.get("boards." + Preferences.get("board") + ".bootloader.extended_fuses")
        != null)
      fuses.add(
          "-Uefuse:w:"
              + Preferences.get("boards." + Preferences.get("board") + ".bootloader.extended_fuses")
              + ":m");
    fuses.add(
        "-Uhfuse:w:"
            + Preferences.get("boards." + Preferences.get("board") + ".bootloader.high_fuses")
            + ":m");
    fuses.add(
        "-Ulfuse:w:"
            + Preferences.get("boards." + Preferences.get("board") + ".bootloader.low_fuses")
            + ":m");

    if (!avrdude(params, fuses)) return false;

    List bootloader = new ArrayList();
    bootloader.add(
        "-Uflash:w:"
            + "hardware"
            + File.separator
            + "bootloaders"
            + File.separator
            + Preferences.get("boards." + Preferences.get("board") + ".bootloader.path")
            + File.separator
            + Preferences.get("boards." + Preferences.get("board") + ".bootloader.file")
            + ":i");
    bootloader.add(
        "-Ulock:w:"
            + Preferences.get("boards." + Preferences.get("board") + ".bootloader.lock_bits")
            + ":m");

    return avrdude(params, bootloader);
  }
  private Collection getProgrammerCommands(String programmer) {
    List params = new ArrayList();
    params.add("-c" + Preferences.get("programmers." + programmer + ".protocol"));

    if ("usb".equals(Preferences.get("programmers." + programmer + ".communication"))) {
      params.add("-Pusb");
    } else if ("serial".equals(Preferences.get("programmers." + programmer + ".communication"))) {
      params.add("-P" + (Base.isWindows() ? "\\\\.\\" : "") + Preferences.get("serial.port"));
      // XXX: add support for specifying the baud rate for serial programmers.
    }
    // XXX: add support for specifying the port address for parallel
    // programmers, although avrdude has a default that works in most cases.

    if (Preferences.get("programmers." + programmer + ".force") != null
        && Preferences.getBoolean("programmers." + programmer + ".force")) params.add("-F");

    if (Preferences.get("programmers." + programmer + ".delay") != null)
      params.add("-i" + Preferences.get("programmers." + programmer + ".delay"));

    return params;
  }
  private boolean uploadViaBootloader(String buildPath, String className) throws RunnerException {
    List commandDownloader = new ArrayList();
    String protocol = Preferences.get("boards." + Preferences.get("board") + ".upload.protocol");

    // avrdude wants "stk500v1" to distinguish it from stk500v2
    if (protocol.equals("stk500")) protocol = "stk500v1";
    commandDownloader.add("-c" + protocol);
    commandDownloader.add(
        "-P" + (Base.isWindows() ? "\\\\.\\" : "") + Preferences.get("serial.port"));
    commandDownloader.add(
        "-b" + Preferences.getInteger("boards." + Preferences.get("board") + ".upload.speed"));
    commandDownloader.add("-D"); // don't erase
    commandDownloader.add("-Uflash:w:" + buildPath + File.separator + className + ".hex:i");

    if (Preferences.get("boards." + Preferences.get("board") + ".upload.disable_flushing") == null
        || Preferences.getBoolean("boards." + Preferences.get("board") + ".upload.disable_flushing")
            == false) {
      flushSerialBuffer();
    }

    return avrdude(commandDownloader);
  }