new boards menu with custom submenus

https://code.google.com/p/arduino/issues/detail?id=257
This commit is contained in:
Federico Fissore 2012-10-29 16:40:23 +01:00
parent cf4d72c043
commit 9b7f473fae
8 changed files with 398 additions and 206 deletions

View File

@ -34,9 +34,11 @@ import javax.swing.filechooser.FileNameExtensionFilter;
import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatform;
import processing.app.helpers.FileUtils;
import processing.app.helpers.Maps;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.filefilters.OnlyDirs;
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
import processing.app.tools.MapWithSubkeys;
import processing.app.tools.ZipDeflater;
import processing.core.*;
import static processing.app.I18n._;
@ -1121,18 +1123,19 @@ public class Base {
editor.onBoardOrPortChange();
}
public void rebuildBoardsMenu(JMenu boardsMenu, final JMenu cpuTypeMenu, final Editor editor) {
public void rebuildBoardsMenu(JMenu toolsMenu, final Editor editor) {
JMenu boardsMenu = makeOrGetBoardMenu(toolsMenu, "Board");
String selPackage = Preferences.get("target_package");
String selPlatform = Preferences.get("target_platform");
String selBoard = Preferences.get("board");
String selBoardContainer = Preferences.get("board_container");
boardsMenu.removeAll();
boolean first = true;
List<JMenuItem> menuItemsToClickAfterStartup = new LinkedList<JMenuItem>();
ButtonGroup boardsButtonGroup = new ButtonGroup();
ButtonGroup cpuTypesButtonGroup = new ButtonGroup();
Map<String, ButtonGroup> buttonGroupsMap = new HashMap<String, ButtonGroup>();
// Cycle through all packages
for (TargetPackage targetPackage : packages.values()) {
@ -1142,115 +1145,160 @@ public class Base {
for (TargetPlatform targetPlatform : targetPackage.platforms()) {
String platformName = targetPlatform.getName();
Map<String, PreferencesMap> boards = targetPlatform.getBoards();
if (targetPlatform.getPreferences().get("name") == null || targetPlatform.getOrderedBoards().isEmpty()) {
continue;
}
// Add a title for each group of boards
if (!first)
if (!first) {
boardsMenu.add(new JSeparator());
first = false;
}
first = false;
JMenuItem separator = new JMenuItem(targetPlatform.getPreferences().get("name"));
separator.setEnabled(false);
boardsMenu.add(separator);
// For every platform cycle through all boards
for (String boardID : targetPlatform.getOrderedBoards()) {
for (final String boardID : targetPlatform.getOrderedBoards()) {
PreferencesMap boardAttributes = boards.get(boardID);
final String boardContainer = boardAttributes.get("container");
AbstractAction filterCPUTypeMenuAction = new AbstractAction() {
AbstractAction action = new AbstractAction(boardAttributes.get("name")) {
@Override
public void actionPerformed(ActionEvent e) {
Preferences.set("board_container", (String) getValue("board_container"));
cpuTypeMenu.setEnabled(true);
for (int i = 0; i < cpuTypeMenu.getItemCount(); i++) {
JMenuItem cpuTypeMenuItem = cpuTypeMenu.getItem(i);
boolean visible = boardContainer.equals(cpuTypeMenuItem.getAction().getValue("board_container"));
cpuTypeMenuItem.setVisible(visible);
}
JMenuItem selectSelectedOrFirstVisibleMenuItem = selectVisibleSelectedOrFirstMenuItem(cpuTypeMenu);
selectSelectedOrFirstVisibleMenuItem.doClick();
}
};
filterCPUTypeMenuAction.putValue("board_container", boardContainer);
@SuppressWarnings("serial")
final AbstractAction selectBoardAction = new AbstractAction(boardAttributes.get("cpu")) {
public void actionPerformed(ActionEvent actionevent) {
Preferences.set("target_package", (String) getValue("package"));
Preferences.set("target_platform", (String) getValue("platform"));
Preferences.set("board", (String) getValue("board"));
filterVisibilityOfSubsequentBoardMenus((String) getValue("board"), 1, e);
onBoardOrPortChange();
Sketch.buildSettingChanged();
rebuildImportMenu(Editor.importMenu, editor);
rebuildExamplesMenu(Editor.examplesMenu);
}
};
selectBoardAction.putValue("package", packageName);
selectBoardAction.putValue("platform", platformName);
selectBoardAction.putValue("board", boardID);
selectBoardAction.putValue("board_container", boardContainer);
if (boardContainer != null) {
findOrCreateBoardContainerMenu(boardsMenu, boardsButtonGroup, boardContainer, filterCPUTypeMenuAction);
JMenuItem item = new JRadioButtonMenuItem(selectBoardAction);
cpuTypesButtonGroup.add(item);
cpuTypeMenu.add(item);
} else {
AbstractAction selectBoardWithoutContainerAction = new AbstractAction(boardAttributes.get("name")) {
@Override
public void actionPerformed(ActionEvent e) {
cpuTypeMenu.setEnabled(false);
Preferences.unset("board_container");
selectBoardAction.actionPerformed(e);
};
action.putValue("properties", boardAttributes);
action.putValue("board", boardID);
action.putValue("package", packageName);
action.putValue("platform", platformName);
JRadioButtonMenuItem item = new JRadioButtonMenuItem(action);
boardsMenu.add(item);
boardsButtonGroup.add(item);
if (selBoard.equals(action.getValue("board")) && selPackage.equals(action.getValue("package"))
&& selPlatform.equals(action.getValue("platform"))) {
menuItemsToClickAfterStartup.add(item);
}
if (targetPlatform.getCustomMenus() != null) {
List<String> customMenuIDs = new LinkedList<String>(targetPlatform.getCustomMenus().getKeys());
for (int i = 0; i < customMenuIDs.size(); i++) {
final String customMenuID = customMenuIDs.get(i);
JMenu menu = makeOrGetBoardMenu(toolsMenu, _(targetPlatform.getCustomMenus().getValueOf(customMenuID)));
MapWithSubkeys customMenu = targetPlatform.getCustomMenus().get(customMenuID);
if (customMenu.getKeys().contains(boardID)) {
MapWithSubkeys boardCustomMenu = customMenu.get(boardID);
final int currentIndex = i + 1 + 1; //plus 1 to skip the first board menu, plus 1 to keep the custom menu next to this one
for (final String customMenuOption : boardCustomMenu.getKeys()) {
action = new AbstractAction(_(boardCustomMenu.getValueOf(customMenuOption))) {
@Override
public void actionPerformed(ActionEvent e) {
Preferences.set("target_package", (String) getValue("package"));
Preferences.set("target_platform", (String) getValue("platform"));
Preferences.set("board", (String) getValue("board"));
Preferences.set("custom_" + customMenuID, boardID + "_" + (String) getValue("custom_menu_option"));
filterVisibilityOfSubsequentBoardMenus((String) getValue("board"), currentIndex, e);
onBoardOrPortChange();
Sketch.buildSettingChanged();
rebuildImportMenu(Editor.importMenu, editor);
rebuildExamplesMenu(Editor.examplesMenu);
}
};
action.putValue("properties", boardCustomMenu.getValues());
action.putValue("board", boardID);
action.putValue("custom_menu_option", customMenuOption);
action.putValue("package", packageName);
action.putValue("platform", platformName);
if (!buttonGroupsMap.containsKey(customMenuID)) {
buttonGroupsMap.put(customMenuID, new ButtonGroup());
}
item = new JRadioButtonMenuItem(action);
menu.add(item);
buttonGroupsMap.get(customMenuID).add(item);
String selectedCustomMenuEntry = Preferences.get("custom_" + customMenuID);
if (selBoard.equals(boardID) && (boardID + "_" + customMenuOption).equals(selectedCustomMenuEntry)) {
menuItemsToClickAfterStartup.add(item);
}
}
}
@Override
public Object getValue(String key) {
return selectBoardAction.getValue(key);
}
@Override
public void putValue(String key, Object newValue) {
selectBoardAction.putValue(key, newValue);
}
};
JMenuItem item = new JRadioButtonMenuItem(selectBoardWithoutContainerAction);
boardsButtonGroup.add(item);
boardsMenu.add(item);
}
}
}
}
}
JMenuItem selectedBoardMenu = selectMenuItemByBoardContainer(boardsMenu, selBoardContainer);
if (selectedBoardMenu == null) {
selectedBoardMenu = selectMenuItemByBoardPackagePlatform(boardsMenu, selBoard, selPackage, selPlatform);
if (selectedBoardMenu == null) {
selectedBoardMenu = selectFirstEnabledMenuItem(boardsMenu);
if (menuItemsToClickAfterStartup.isEmpty()) {
menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardsMenu));
}
for (JMenuItem menuItemToClick : menuItemsToClickAfterStartup) {
menuItemToClick.setSelected(true);
menuItemToClick.getAction().actionPerformed(new ActionEvent(this, -1, ""));
}
}
selectedBoardMenu.doClick();
}
if (cpuTypeMenu.isEnabled()) {
JMenuItem selectedCPUTypeMenu;
if (selBoard == null) {
selectedCPUTypeMenu = selectFirstEnabledMenuItem(cpuTypeMenu);
} else {
selectedCPUTypeMenu = selectMenuItemByBoardPackagePlatform(cpuTypeMenu, selBoard, selPackage, selPlatform);
if (selectedCPUTypeMenu == null) {
selectedCPUTypeMenu = selectFirstEnabledMenuItem(cpuTypeMenu);
private static void filterVisibilityOfSubsequentBoardMenus(String boardID, int fromIndex, ActionEvent originatingEvent) {
for (int i = fromIndex; i < Editor.boardsMenus.size(); i++) {
JMenu menu = Editor.boardsMenus.get(i);
for (int m = 0; m < menu.getItemCount(); m++) {
JMenuItem menuItem = menu.getItem(m);
menuItem.setVisible(menuItem.getAction().getValue("board").equals(boardID));
}
menu.setEnabled(ifThereAreVisibleItemsOn(menu));
if (menu.isEnabled()) {
JMenuItem visibleSelectedOrFirstMenuItem = selectVisibleSelectedOrFirstMenuItem(menu);
if (!visibleSelectedOrFirstMenuItem.isSelected()) {
visibleSelectedOrFirstMenuItem.setSelected(true);
visibleSelectedOrFirstMenuItem.getAction().actionPerformed(originatingEvent);
}
}
selectedCPUTypeMenu.doClick();
}
}
private static boolean ifThereAreVisibleItemsOn(JMenu menu) {
for (int i = 0; i < menu.getItemCount(); i++) {
if (menu.getItem(i).isVisible()) {
return true;
}
}
return false;
}
private JMenu makeOrGetBoardMenu(JMenu toolsMenu, String label) {
String i18nLabel = _(label);
for (JMenu menu : Editor.boardsMenus) {
if (i18nLabel.equals(menu.getText())) {
return menu;
}
}
JMenu menu = new JMenu(i18nLabel);
Editor.boardsMenus.add(menu);
toolsMenu.add(menu);
return menu;
}
private static JMenuItem selectVisibleSelectedOrFirstMenuItem(JMenu menu) {
JMenuItem firstVisible = null;
@ -1283,45 +1331,6 @@ public class Base {
throw new IllegalStateException("Menu has no enabled items");
}
private static JMenuItem selectMenuItemByBoardContainer(JMenu menu, String boardContainer) {
if (boardContainer == null) {
return null;
}
for (int i = 0; i < menu.getItemCount(); i++) {
JMenuItem item = menu.getItem(i);
if (item != null && item.getAction() != null && boardContainer.equals(item.getAction().getValue("board_container"))) {
return item;
}
}
return null;
}
private static JMenuItem selectMenuItemByBoardPackagePlatform(JMenu menu, String selBoard, String selPackage, String selPlatform) {
for (int i = 0; i < menu.getItemCount(); i++) {
JMenuItem item = menu.getItem(i);
if (item != null && item.getAction() != null && selBoard.equals(item.getAction().getValue("board"))
&& selPackage.equals(item.getAction().getValue("package")) && selPlatform.equals(item.getAction().getValue("platform"))) {
return item;
}
}
return null;
}
private JMenuItem findOrCreateBoardContainerMenu(JMenu boardsMenu, ButtonGroup boardsButtonGroup, String boardContainerName, AbstractAction boardMenuAction) {
for (int i = 0; i < boardsMenu.getItemCount(); i++ ) {
JMenuItem boardContainer = boardsMenu.getItem(i);
if (boardContainer != null && boardContainerName.equals(boardContainer.getText())) {
return boardContainer;
}
}
JMenuItem item = new JRadioButtonMenuItem(boardMenuAction);
item.setText(boardContainerName);
boardsButtonGroup.add(item);
boardsMenu.add(item);
return item;
}
public void rebuildProgrammerMenu(JMenu menu) {
menu.removeAll();
ButtonGroup group = new ButtonGroup();
@ -1809,10 +1818,22 @@ public class Base {
return getTargetPlatform(pack, Preferences.get("target_platform"));
}
static public PreferencesMap getBoardPreferences() {
static public Map<String, String> getBoardPreferences() {
TargetPlatform target = getTargetPlatform();
String board = Preferences.get("board");
return target.getBoards().get(board);
Map<String, String> boardPreferences = Maps.merge(target.getBoards().get(board), new LinkedHashMap<String, String>());
if (target.getCustomMenus() != null) {
for (String customMenuID : target.getCustomMenus().getKeys()) {
MapWithSubkeys boardCustomMenu = target.getCustomMenus().get(customMenuID).get(board);
String selectedCustomMenuEntry = Preferences.get("custom_" + customMenuID);
if (boardCustomMenu != null && selectedCustomMenuEntry != null && selectedCustomMenuEntry.startsWith(board)) {
String menuEntryId = selectedCustomMenuEntry.substring(selectedCustomMenuEntry.indexOf("_") + 1);
Maps.merge(boardCustomMenu.get(menuEntryId).getValues(), boardPreferences);
boardPreferences.put("name", boardPreferences.get("name") + ", " + boardCustomMenu.getValueOf(menuEntryId));
}
}
}
return boardPreferences;
}
static public File getSketchbookFolder() {

View File

@ -35,6 +35,7 @@ import java.awt.print.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.List;
import java.util.zip.*;
import javax.swing.*;
@ -95,9 +96,8 @@ public class Editor extends JFrame implements RunnerListener {
// these menus are shared so that the board and serial port selections
// are the same for all windows (since the board and serial port that are
// actually used are determined by the preferences, which are shared)
static JMenu boardsMenu;
static List<JMenu> boardsMenus;
static JMenu serialMenu;
static JMenu cpuTypeMenu;
static SerialMenuListener serialMenuListener;
static SerialMonitor serialMonitor;
@ -178,10 +178,13 @@ public class Editor extends JFrame implements RunnerListener {
// re-add the sub-menus that are shared by all windows
fileMenu.insert(sketchbookMenu, 2);
fileMenu.insert(examplesMenu, 3);
//sketchMenu.insert(importMenu, 4);
toolsMenu.insert(boardsMenu, numTools);
toolsMenu.insert(cpuTypeMenu, numTools + 1);
toolsMenu.insert(serialMenu, numTools + 2);
sketchMenu.insert(importMenu, 4);
int offset = 0;
for (JMenu menu : boardsMenus) {
toolsMenu.insert(menu, numTools + offset);
offset++;
}
toolsMenu.insert(serialMenu, numTools + offset);
}
// added for 1.0.5
@ -190,9 +193,10 @@ public class Editor extends JFrame implements RunnerListener {
// System.err.println("deactivate"); // not coming through
fileMenu.remove(sketchbookMenu);
fileMenu.remove(examplesMenu);
//sketchMenu.remove(importMenu);
toolsMenu.remove(boardsMenu);
toolsMenu.remove(cpuTypeMenu);
sketchMenu.remove(importMenu);
for (JMenu menu : boardsMenus) {
toolsMenu.remove(menu);
}
toolsMenu.remove(serialMenu);
}
});
@ -681,16 +685,13 @@ public class Editor extends JFrame implements RunnerListener {
// XXX: DAM: these should probably be implemented using the Tools plugin
// API, if possible (i.e. if it supports custom actions, etc.)
if (boardsMenu == null) {
boardsMenu = new JMenu(_("Board"));
cpuTypeMenu = new JMenu(_("Processor"));
base.rebuildBoardsMenu(boardsMenu, cpuTypeMenu, this);
if (boardsMenus == null) {
boardsMenus = new LinkedList<JMenu>();
base.rebuildBoardsMenu(toolsMenu, this);
//Debug: rebuild imports
importMenu.removeAll();
base.rebuildImportMenu(importMenu, this);
}
menu.add(boardsMenu);
menu.add(cpuTypeMenu);
if (serialMenuListener == null)
serialMenuListener = new SerialMenuListener();
@ -2660,7 +2661,7 @@ public class Editor extends JFrame implements RunnerListener {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
protected void onBoardOrPortChange() {
Map<String, String> boardPreferences = Base.getBoardPreferences();
Map<String, String> boardPreferences = Base.getBoardPreferences();
lineStatus.setBoardName(boardPreferences.get("name"));
lineStatus.setSerialPort(Preferences.get("serial.port"));
lineStatus.repaint();

View File

@ -30,6 +30,7 @@ import java.util.List;
import java.util.Map;
import processing.app.helpers.PreferencesMap;
import processing.app.tools.MapWithSubkeys;
import processing.core.PApplet;
public class TargetPlatform {
@ -39,6 +40,7 @@ public class TargetPlatform {
private List<String> boardsOrder;
private Map<String, PreferencesMap> programmers;
private PreferencesMap preferences;
private MapWithSubkeys customMenus;
public TargetPlatform(String _name, File _folder) {
System.out.println("TargetPlatform: constructor start, name: " + _name);
@ -55,9 +57,12 @@ public class TargetPlatform {
PreferencesMap boardPreferences = new PreferencesMap();
boardPreferences.load(boardsFile);
boards = boardPreferences.createFirstLevelMap();
customMenus = MapWithSubkeys.createFrom(boards.get("menu"));
boards.remove("menu");
boardsOrder = readBoardsOrder(boardsFile);
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("Error loading boards from boards.txt: " + e);
}
@ -119,7 +124,11 @@ public class TargetPlatform {
public Map<String, PreferencesMap> getBoards() {
return boards;
}
public MapWithSubkeys getCustomMenus() {
return customMenus;
}
public List<String> getOrderedBoards() {
return boardsOrder;
}

View File

@ -0,0 +1,15 @@
package processing.app.helpers;
import java.util.Map;
import java.util.Map.Entry;
public class Maps {
public static <K, V> Map<K, V> merge(Map<K, V> input, Map<K, V> target) {
for (Entry<K, V> entry : input.entrySet()) {
target.put(entry.getKey(), entry.getValue());
}
return target;
}
}

View File

@ -0,0 +1,66 @@
package processing.app.tools;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class MapWithSubkeys {
public static MapWithSubkeys createFrom(Map<String, String> input) {
if (input == null) {
return null;
}
MapWithSubkeys target = new MapWithSubkeys();
for (Entry<String, String> entry : input.entrySet()) {
String[] entryParts = entry.getKey().split("\\.");
if (entryParts.length == 1) {
target.put(entryParts[0], entry.getValue());
} else if (entryParts.length == 3) {
target.get(entryParts[0]).get(entryParts[1]).put(entryParts[2], entry.getValue());
} else if (entryParts.length > 3) {
StringBuilder sb = new StringBuilder();
for (int i = 3; i < entryParts.length; i++) {
sb.append(entryParts[i]).append(".");
}
sb.deleteCharAt(sb.length() - 1);
String key = sb.toString();
target.get(entryParts[0]).get(entryParts[1]).get(entryParts[2]).put(key, entry.getValue());
}
}
return target;
}
private final Map<String, String> values;
private final Map<String, MapWithSubkeys> maps;
public MapWithSubkeys() {
this.values = new HashMap<String, String>();
this.maps = new HashMap<String, MapWithSubkeys>();
}
public Collection<String> getKeys() {
return values.keySet();
}
public Map<String, String> getValues() {
return values;
}
public String getValueOf(String key) {
return values.get(key);
}
public MapWithSubkeys get(String key) {
if (!maps.containsKey(key)) {
put(key, null);
maps.put(key, new MapWithSubkeys());
}
return maps.get(key);
}
public void put(String key, String value) {
values.put(key, value);
}
}

View File

@ -0,0 +1,59 @@
package processing.app.tools;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
public class MapWithSubkeysTest {
private MapWithSubkeys map;
@Before
public void setup() throws Exception {
Map<String, String> input = new HashMap<String, String>();
BufferedReader reader = new BufferedReader(new InputStreamReader(MapWithSubkeysTest.class.getResourceAsStream("test_partial_boards.txt")));
String line = null;
while ((line = reader.readLine()) != null) {
String[] lineParts = line.split("=");
input.put(lineParts[0], lineParts[1]);
}
map = MapWithSubkeys.createFrom(input);
}
@Test
public void shouldListCustomMenusIDs() {
Collection<String> menusIDs = map.getKeys();
assertEquals(2, menusIDs.size());
assertTrue(menusIDs.contains("cpu"));
assertTrue(menusIDs.contains("speed"));
assertEquals("Processor", map.getValueOf("cpu"));
MapWithSubkeys cpu = map.get("cpu");
Collection<String> boards = cpu.getKeys();
assertEquals(1, boards.size());
assertTrue(boards.contains("nano"));
Collection<String> cpuNanoProcessors = cpu.get("nano").getKeys();
assertEquals(2, cpuNanoProcessors.size());
assertTrue(cpuNanoProcessors.contains("atmega168"));
assertTrue(cpuNanoProcessors.contains("atmega328"));
assertEquals("ATmega168", cpu.get("nano").getValueOf("atmega168"));
assertEquals("ATmega328", cpu.get("nano").getValueOf("atmega328"));
MapWithSubkeys atmega168Properties = cpu.get("nano").get("atmega168");
assertEquals(9, atmega168Properties.getKeys().size());
assertTrue(atmega168Properties.getKeys().contains("bootloader.high_fuses"));
}
}

View File

@ -0,0 +1,26 @@
cpu=Processor
cpu.nano.atmega328=ATmega328
cpu.nano.atmega328.upload.maximum_size=30720
cpu.nano.atmega328.upload.speed=57600
cpu.nano.atmega328.bootloader.low_fuses=0xFF
cpu.nano.atmega328.bootloader.high_fuses=0xDA
cpu.nano.atmega328.bootloader.extended_fuses=0x05
cpu.nano.atmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex
cpu.nano.atmega328.bootloader.unlock_bits=0x3F
cpu.nano.atmega328.bootloader.lock_bits=0x0F
cpu.nano.atmega328.build.mcu=atmega328p
cpu.nano.atmega168=ATmega168
cpu.nano.atmega168.upload.maximum_size=14336
cpu.nano.atmega168.upload.speed=19200
cpu.nano.atmega168.bootloader.low_fuses=0xff
cpu.nano.atmega168.bootloader.high_fuses=0xdd
cpu.nano.atmega168.bootloader.extended_fuses=0x00
cpu.nano.atmega168.bootloader.file=atmega/ATmegaBOOT_168_diecimila.hex
cpu.nano.atmega168.bootloader.unlock_bits=0x3F
cpu.nano.atmega168.bootloader.lock_bits=0x0F
cpu.nano.atmega168.build.mcu=atmega168
speed=Speed
speed.nano.16=16 MHz
speed.nano.16.build.f_cpu=16000000L
speed.nano.8=8 MHz
speed.nano.8.build.f_cpu=8000000L

View File

@ -1,5 +1,9 @@
# See: http://code.google.com/p/arduino/wiki/Platforms
menu.cpu=Processor
#FIXME
menu.speed=Speed
##############################################################
uno.name=Arduino Uno
@ -67,52 +71,45 @@ diecimila.build.variant=standard
##############################################################
nano328.name=Arduino Nano w/ ATmega328
nano328.cpu=ATmega328
nano328.container=Arduino Nano
nano328.upload.tool=avrdude
nano328.upload.protocol=arduino
nano328.upload.maximum_size=30720
nano328.upload.speed=57600
nano328.bootloader.tool=avrdude
nano328.bootloader.low_fuses=0xFF
nano328.bootloader.high_fuses=0xDA
nano328.bootloader.extended_fuses=0x05
nano328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex
nano328.bootloader.unlock_bits=0x3F
nano328.bootloader.lock_bits=0x0F
nano328.build.mcu=atmega328p
nano328.build.f_cpu=16000000L
nano328.build.core=arduino
nano328.build.variant=eightanaloginputs
##############################################################
nano.name=Arduino Nano w/ ATmega168
nano.cpu=ATmega168
nano.container=Arduino Nano
nano.name=Arduino Nano
nano.upload.tool=avrdude
nano.upload.protocol=arduino
nano.upload.maximum_size=14336
nano.upload.speed=19200
nano.bootloader.tool=avrdude
nano.bootloader.low_fuses=0xff
nano.bootloader.high_fuses=0xdd
nano.bootloader.extended_fuses=0x00
nano.bootloader.file=atmega/ATmegaBOOT_168_diecimila.hex
nano.bootloader.unlock_bits=0x3F
nano.bootloader.lock_bits=0x0F
nano.build.mcu=atmega168
nano.build.f_cpu=16000000L
nano.build.core=arduino
nano.build.variant=eightanaloginputs
#Arduino Nano w/ ATmega328
menu.cpu.nano.atmega328=ATmega328
menu.cpu.nano.atmega328.upload.maximum_size=30720
menu.cpu.nano.atmega328.upload.speed=57600
menu.cpu.nano.atmega328.bootloader.low_fuses=0xFF
menu.cpu.nano.atmega328.bootloader.high_fuses=0xDA
menu.cpu.nano.atmega328.bootloader.extended_fuses=0x05
menu.cpu.nano.atmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex
menu.cpu.nano.atmega328.bootloader.unlock_bits=0x3F
menu.cpu.nano.atmega328.bootloader.lock_bits=0x0F
menu.cpu.nano.atmega328.build.mcu=atmega328p
#Arduino Nano w/ ATmega168
menu.cpu.nano.atmega168=ATmega168
menu.cpu.nano.atmega168.upload.maximum_size=14336
menu.cpu.nano.atmega168.upload.speed=19200
menu.cpu.nano.atmega168.bootloader.low_fuses=0xff
menu.cpu.nano.atmega168.bootloader.high_fuses=0xdd
menu.cpu.nano.atmega168.bootloader.extended_fuses=0x00
menu.cpu.nano.atmega168.bootloader.file=atmega/ATmegaBOOT_168_diecimila.hex
menu.cpu.nano.atmega168.bootloader.unlock_bits=0x3F
menu.cpu.nano.atmega168.bootloader.lock_bits=0x0F
menu.cpu.nano.atmega168.build.mcu=atmega168
##############################################################
mega2560.name=Arduino Mega 2560 or Mega ADK
@ -190,52 +187,50 @@ leonardo.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}
##############################################################
mini328.name=Arduino Mini w/ ATmega328
mini328.cpu=ATmega328
mini328.container=Arduino Mini
mini328.upload.tool=avrdude
mini328.upload.protocol=arduino
mini328.upload.maximum_size=28672
mini328.upload.speed=115200
mini328.bootloader.tool=avrdude
mini328.bootloader.low_fuses=0xff
mini328.bootloader.high_fuses=0xd8
mini328.bootloader.extended_fuses=0x05
mini328.bootloader.file=optiboot/optiboot_atmega328-Mini.hex
mini328.bootloader.unlock_bits=0x3F
mini328.bootloader.lock_bits=0x0F
mini328.build.mcu=atmega328p
mini328.build.f_cpu=16000000L
mini328.build.core=arduino
mini328.build.variant=eightanaloginputs
##############################################################
mini.name=Arduino Mini w/ ATmega168
mini.cpu=ATmega168
mini.container=Arduino Mini
mini.name=Arduino Mini
mini.upload.tool=avrdude
mini.upload.protocol=arduino
mini.upload.maximum_size=14336
mini.upload.speed=19200
mini.bootloader.tool=avrdude
mini.bootloader.low_fuses=0xff
mini.bootloader.high_fuses=0xdd
mini.bootloader.extended_fuses=0x00
mini.bootloader.file=atmega/ATmegaBOOT_168_ng.hex
mini.bootloader.unlock_bits=0x3F
mini.bootloader.lock_bits=0x0F
mini.build.mcu=atmega168
mini.build.f_cpu=16000000L
mini.build.core=arduino
mini.build.variant=eightanaloginputs
#Arduino Mini w/ ATmega328
menu.cpu.mini.atmega328=ATmega328
menu.cpu.mini.atmega328.upload.maximum_size=28672
menu.cpu.mini.atmega328.upload.speed=115200
menu.cpu.mini.atmega328.bootloader.high_fuses=0xd8
menu.cpu.mini.atmega328.bootloader.extended_fuses=0x05
menu.cpu.mini.atmega328.bootloader.file=optiboot/optiboot_atmega328-Mini.hex
menu.cpu.mini.atmega328.build.mcu=atmega328p
#Arduino Mini w/ ATmega168
menu.cpu.mini.atmega168=ATmega168
menu.cpu.mini.atmega168.upload.maximum_size=14336
menu.cpu.mini.atmega168.upload.speed=19200
menu.cpu.mini.atmega168.bootloader.high_fuses=0xdd
menu.cpu.mini.atmega168.bootloader.extended_fuses=0x00
menu.cpu.mini.atmega168.bootloader.file=atmega/ATmegaBOOT_168_ng.hex
menu.cpu.mini.atmega168.build.mcu=atmega168
#FIXME
menu.speed.mini.16=16 MHz
menu.speed.mini.16.build.f_cpu=16000000L
menu.speed.mini.8=8 MHz
menu.speed.mini.8.build.f_cpu=8000000L
##############################################################
ethernet.name=Arduino Ethernet