Arduino Library Support
authorDoug Schaefer <dschaefer@qnx.com>
Sun, 23 Aug 2015 02:26:30 +0000 (22:26 -0400)
committerGerrit Code Review @ Eclipse.org <gerrit@eclipse.org>
Tue, 25 Aug 2015 03:16:19 +0000 (23:16 -0400)
Change-Id: Ifdc9075beba4002b1481576d07ed2d8d44e5c2da

17 files changed:
toolchains/arduino/org.eclipse.cdt.arduino.core.tests/src/org/eclipse/cdt/arduino/core/tests/BoardManagerTests.java
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/ArduinoProjectGenerator.java
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoLibrary.java [new file with mode: 0644]
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoManager.java [moved from toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoBoardManager.java with 68% similarity]
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPackage.java
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoPlatform.java
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoToolSystem.java
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java [new file with mode: 0644]
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/PackageIndex.java
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/build/ArduinoBuildConfiguration.java
toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/remote/ArduinoRemoteConnection.java
toolchains/arduino/org.eclipse.cdt.arduino.core/templates/board.mk
toolchains/arduino/org.eclipse.cdt.arduino.ui/plugin.xml
toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/preferences/ArduinoBoardsPreferencePage.java
toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/LibrariesPropertyPage.java [new file with mode: 0644]
toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/ArduinoTargetPropertyPage.java
toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/remote/NewArduinoTargetWizardPage.java

index 862f9ad..8641687 100644 (file)
@@ -2,14 +2,14 @@ package org.eclipse.cdt.arduino.core.tests;
 
 import static org.junit.Assert.assertNotNull;
 
-import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoardManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.junit.Test;
 
 public class BoardManagerTests {
 
        @Test
        public void loadPackagesTest() throws Exception {
-               assertNotNull(ArduinoBoardManager.instance.getPackageIndex());
+               assertNotNull(ArduinoManager.instance.getPackageIndex());
        }
 
 }
index c74b7a2..ccf7346 100644 (file)
@@ -14,7 +14,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
-import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoardManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration;
 import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuilder;
 import org.eclipse.cdt.core.CCProjectNature;
@@ -64,7 +64,7 @@ public class ArduinoProjectGenerator {
 
                IBuildConfiguration config = project.getBuildConfig("uno"); //$NON-NLS-1$
                ArduinoBuildConfiguration arduinoConfig = config.getAdapter(ArduinoBuildConfiguration.class);
-               ArduinoBoard board = ArduinoBoardManager.instance.getBoard("Arduino Uno", "Arduino AVR Boards", "arduino"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+               ArduinoBoard board = ArduinoManager.instance.getBoard("Arduino Uno", "Arduino AVR Boards", "arduino"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                arduinoConfig.setBoard(board);
 
                // Generate files
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoLibrary.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/ArduinoLibrary.java
new file mode 100644 (file)
index 0000000..31ea505
--- /dev/null
@@ -0,0 +1,204 @@
+package org.eclipse.cdt.arduino.core.internal.board;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+public class ArduinoLibrary {
+
+       private String name;
+       private String version;
+       private String author;
+       private String maintainer;
+       private String sentence;
+       private String paragraph;
+       private String website;
+       private String category;
+       private List<String> architectures;
+       private List<String> types;
+       private String url;
+       private String archiveFileName;
+       private int size;
+       private String checksum;
+
+       public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       public String getVersion() {
+               return version;
+       }
+
+       public void setVersion(String version) {
+               this.version = version;
+       }
+
+       public String getAuthor() {
+               return author;
+       }
+
+       public void setAuthor(String author) {
+               this.author = author;
+       }
+
+       public String getMaintainer() {
+               return maintainer;
+       }
+
+       public void setMaintainer(String maintainer) {
+               this.maintainer = maintainer;
+       }
+
+       public String getSentence() {
+               return sentence;
+       }
+
+       public void setSentence(String sentence) {
+               this.sentence = sentence;
+       }
+
+       public String getParagraph() {
+               return paragraph;
+       }
+
+       public void setParagraph(String paragraph) {
+               this.paragraph = paragraph;
+       }
+
+       public String getWebsite() {
+               return website;
+       }
+
+       public void setWebsite(String website) {
+               this.website = website;
+       }
+
+       public String getCategory() {
+               return category;
+       }
+
+       public void setCategory(String category) {
+               this.category = category;
+       }
+
+       public List<String> getArchitectures() {
+               return architectures;
+       }
+
+       public void setArchitectures(List<String> architectures) {
+               this.architectures = architectures;
+       }
+
+       public List<String> getTypes() {
+               return types;
+       }
+
+       public void setTypes(List<String> types) {
+               this.types = types;
+       }
+
+       public String getUrl() {
+               return url;
+       }
+
+       public void setUrl(String url) {
+               this.url = url;
+       }
+
+       public String getArchiveFileName() {
+               return archiveFileName;
+       }
+
+       public void setArchiveFileName(String archiveFileName) {
+               this.archiveFileName = archiveFileName;
+       }
+
+       public int getSize() {
+               return size;
+       }
+
+       public void setSize(int size) {
+               this.size = size;
+       }
+
+       public String getChecksum() {
+               return checksum;
+       }
+
+       public void setChecksum(String checksum) {
+               this.checksum = checksum;
+       }
+
+       public Path getInstallPath() {
+               return ArduinoPreferences.getArduinoHome().resolve("libraries").resolve(name.replace(' ', '_')) //$NON-NLS-1$
+                               .resolve(version);
+       }
+
+       public boolean isInstalled() {
+               return getInstallPath().toFile().exists();
+       }
+
+       public IStatus install(IProgressMonitor monitor) {
+               if (isInstalled()) {
+                       return Status.OK_STATUS;
+               }
+
+               return ArduinoManager.downloadAndInstall(url, archiveFileName, getInstallPath(), monitor);
+       }
+
+       public Collection<Path> getIncludePath() {
+               Path installPath = getInstallPath();
+               Path srcPath = installPath.resolve("src"); //$NON-NLS-1$
+               if (srcPath.toFile().isDirectory()) {
+                       return Collections.singletonList(srcPath);
+               } else {
+                       // TODO do I need the 'utility' directory?
+                       return Collections.singletonList(installPath);
+               }
+       }
+
+       private void getSources(IProject project, Collection<Path> sources, Path dir, boolean recurse) {
+               for (File file : dir.toFile().listFiles()) {
+                       if (file.isDirectory()) {
+                               if (recurse) {
+                                       getSources(project, sources, file.toPath(), recurse);
+                               }
+                       } else {
+                               if (CoreModel.isValidSourceUnitName(project, file.getName())) {
+                                       sources.add(file.toPath());
+                               }
+                       }
+               }
+       }
+
+       public Collection<Path> getSources(IProject project) {
+               List<Path> sources = new ArrayList<>();
+               Path installPath = getInstallPath();
+               Path srcPath = installPath.resolve("src"); //$NON-NLS-1$
+               if (srcPath.toFile().isDirectory()) {
+                       getSources(project, sources, srcPath, true);
+               } else {
+                       getSources(project, sources, installPath, false);
+                       Path utilityPath = installPath.resolve("utility"); //$NON-NLS-1$
+                       if (utilityPath.toFile().isDirectory()) {
+                               getSources(project, sources, utilityPath, false);
+                       }
+               }
+               return sources;
+       }
+
+}
@@ -16,12 +16,14 @@ import java.io.FileInputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Type;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -36,19 +38,26 @@ import org.apache.commons.compress.compressors.CompressorStreamFactory;
 import org.eclipse.cdt.arduino.core.internal.Activator;
 import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences;
 import org.eclipse.cdt.arduino.core.internal.Messages;
+import org.eclipse.cdt.arduino.core.internal.build.ArduinoBuildConfiguration;
+import org.eclipse.core.resources.IBuildConfiguration;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ProjectScope;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.osgi.service.prefs.BackingStoreException;
 
 import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
 
-// Closeable isn't API yet but it's recommended.
-public class ArduinoBoardManager {
+public class ArduinoManager {
 
-       public static final ArduinoBoardManager instance = new ArduinoBoardManager();
+       public static final ArduinoManager instance = new ArduinoManager();
 
        // Build tool ids
        public static final String BOARD_OPTION_ID = "org.eclipse.cdt.arduino.option.board"; //$NON-NLS-1$
@@ -59,13 +68,25 @@ public class ArduinoBoardManager {
        private Path packageIndexPath = ArduinoPreferences.getArduinoHome().resolve("package_index.json"); //$NON-NLS-1$
        private PackageIndex packageIndex;
 
-       public ArduinoBoardManager() {
+       private Path libraryIndexPath = ArduinoPreferences.getArduinoHome().resolve("library_index.json"); //$NON-NLS-1$
+       private LibraryIndex libraryIndex;
+
+       public ArduinoManager() {
                new Job(Messages.ArduinoBoardManager_0) {
                        protected IStatus run(IProgressMonitor monitor) {
                                try {
-                                       URL url = new URL("http://downloads.arduino.cc/packages/package_index.json"); //$NON-NLS-1$
+                                       // library index has the same parent right now
                                        Files.createDirectories(packageIndexPath.getParent());
-                                       Files.copy(url.openStream(), packageIndexPath, StandardCopyOption.REPLACE_EXISTING);
+
+                                       URL packageUrl = new URL("http://downloads.arduino.cc/packages/package_index.json"); //$NON-NLS-1$
+                                       try (InputStream in = packageUrl.openStream()) {
+                                               Files.copy(in, packageIndexPath, StandardCopyOption.REPLACE_EXISTING);
+                                       }
+
+                                       URL libraryUrl = new URL("http://downloads.arduino.cc/libraries/library_index.json"); //$NON-NLS-1$
+                                       try (InputStream in = libraryUrl.openStream()) {
+                                               Files.copy(in, libraryIndexPath, StandardCopyOption.REPLACE_EXISTING);
+                                       }
                                } catch (IOException e) {
                                        return new Status(IStatus.ERROR, Activator.getId(), e.getLocalizedMessage(), e);
                                }
@@ -86,6 +107,18 @@ public class ArduinoBoardManager {
                return packageIndex;
        }
 
+       public LibraryIndex getLibraryIndex() throws CoreException {
+               if (libraryIndex == null) {
+                       try (FileReader reader = new FileReader(libraryIndexPath.toFile())) {
+                               libraryIndex = new Gson().fromJson(reader, LibraryIndex.class);
+                               libraryIndex.resolve();
+                       } catch (IOException e) {
+                               throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Reading library index", e));
+                       }
+               }
+               return libraryIndex;
+       }
+
        public ArduinoBoard getBoard(String boardName, String platformName, String packageName) throws CoreException {
                return getPackageIndex().getPackage(packageName).getPlatform(platformName).getBoard(boardName);
        }
@@ -115,6 +148,63 @@ public class ArduinoBoardManager {
                return pkg != null ? pkg.getTool(toolName, version) : null;
        }
 
+       private static final String LIBRARIES = "libraries"; //$NON-NLS-1$
+
+       private IEclipsePreferences getSettings(IProject project) {
+               return (IEclipsePreferences) new ProjectScope(project).getNode(Activator.getId());
+       }
+
+       public Collection<ArduinoLibrary> getLibraries(IProject project) throws CoreException {
+               IEclipsePreferences settings = getSettings(project);
+               String librarySetting = settings.get(LIBRARIES, "[]"); //$NON-NLS-1$
+               Type stringSet = new TypeToken<Set<String>>() {
+               }.getType();
+               Set<String> libraryNames = new Gson().fromJson(librarySetting, stringSet);
+               LibraryIndex index = ArduinoManager.instance.getLibraryIndex();
+               List<ArduinoLibrary> libraries = new ArrayList<>(libraryNames.size());
+               for (String name : libraryNames) {
+                       libraries.add(index.getLibrary(name));
+               }
+               return libraries;
+       }
+
+       public void setLibraries(final IProject project, final Collection<ArduinoLibrary> libraries) throws CoreException {
+               List<String> libraryNames = new ArrayList<>(libraries.size());
+               for (ArduinoLibrary library : libraries) {
+                       libraryNames.add(library.getName());
+               }
+               IEclipsePreferences settings = getSettings(project);
+               settings.put(LIBRARIES, new Gson().toJson(libraryNames));
+               try {
+                       settings.flush();
+               } catch (BackingStoreException e) {
+                       throw new CoreException(new Status(IStatus.ERROR, Activator.getId(), "Saving preferences", e));
+               }
+
+               new Job("Install libraries") {
+                       protected IStatus run(IProgressMonitor monitor) {
+                               MultiStatus mstatus = new MultiStatus(Activator.getId(), 0, "Installing libraries", null);
+                               for (ArduinoLibrary library : libraries) {
+                                       IStatus status = library.install(monitor);
+                                       if (!status.isOK()) {
+                                               mstatus.add(status);
+                                       }
+                               }
+
+                               // Clear the scanner info caches to pick up new includes
+                               try {
+                                       for (IBuildConfiguration config : project.getBuildConfigs()) {
+                                               ArduinoBuildConfiguration arduinoConfig = config.getAdapter(ArduinoBuildConfiguration.class);
+                                               arduinoConfig.clearScannerInfoCache();
+                                       }
+                               } catch (CoreException e) {
+                                       mstatus.add(e.getStatus());
+                               }
+                               return mstatus;
+                       }
+               }.schedule();
+       }
+
        public static IStatus downloadAndInstall(String url, String archiveFileName, Path installPath,
                        IProgressMonitor monitor) {
                try {
index 168e6af..39f8329 100644 (file)
@@ -13,8 +13,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.eclipse.core.runtime.IProgressMonitor;
-
 public class ArduinoPackage {
 
        private String name;
@@ -25,9 +23,9 @@ public class ArduinoPackage {
        private List<ArduinoPlatform> platforms;
        private List<ArduinoTool> tools;
 
-       private transient ArduinoBoardManager manager;
+       private transient ArduinoManager manager;
 
-       void setOwner(ArduinoBoardManager manager) {
+       void setOwner(ArduinoManager manager) {
                this.manager = manager;
                for (ArduinoPlatform platform : platforms) {
                        platform.setOwner(this);
@@ -37,7 +35,7 @@ public class ArduinoPackage {
                }
        }
 
-       ArduinoBoardManager getManager() {
+       ArduinoManager getManager() {
                return manager;
        }
 
@@ -94,7 +92,8 @@ public class ArduinoPackage {
                return Collections.unmodifiableCollection(platformMap.values());
        }
 
-       private int compareVersions(String version1, String version2) {
+       // TODO move somewhere.
+       public static int compareVersions(String version1, String version2) {
                if (version1 == null) {
                        return version2 == null ? 0 : -1;
                }
@@ -169,10 +168,6 @@ public class ArduinoPackage {
                return null;
        }
 
-       public void install(IProgressMonitor monitor) {
-
-       }
-
        @Override
        public boolean equals(Object obj) {
                if (obj instanceof ArduinoPackage) {
index 9d733f8..5d69391 100644 (file)
@@ -179,7 +179,7 @@ public class ArduinoPlatform {
                }
 
                // Download platform archive
-               IStatus status = ArduinoBoardManager.downloadAndInstall(url, archiveFileName, getInstallPath(), monitor);
+               IStatus status = ArduinoManager.downloadAndInstall(url, archiveFileName, getInstallPath(), monitor);
                if (!status.isOK()) {
                        return status;
                }
index bb994a4..0a5d985 100644 (file)
@@ -72,7 +72,7 @@ public class ArduinoToolSystem {
        }
 
        public IStatus install(IProgressMonitor monitor) {
-               return ArduinoBoardManager.downloadAndInstall(url, archiveFileName, tool.getInstallPath(), monitor);
+               return ArduinoManager.downloadAndInstall(url, archiveFileName, tool.getInstallPath(), monitor);
        }
 
 }
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java b/toolchains/arduino/org.eclipse.cdt.arduino.core/src/org/eclipse/cdt/arduino/core/internal/board/LibraryIndex.java
new file mode 100644 (file)
index 0000000..a0bbef4
--- /dev/null
@@ -0,0 +1,69 @@
+package org.eclipse.cdt.arduino.core.internal.board;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class LibraryIndex {
+
+       private List<ArduinoLibrary> libraries;
+
+       // category name to library name
+       private Map<String, Set<String>> categories = new HashMap<>();
+       // library name to latest version of library
+       private Map<String, ArduinoLibrary> latestLibs = new HashMap<>();
+
+       public void resolve() {
+               for (ArduinoLibrary library : libraries) {
+                       String name = library.getName();
+
+                       String category = library.getCategory();
+                       if (category == null) {
+                               category = "Uncategorized"; //$NON-NLS-1$
+                       }
+
+                       Set<String> categoryLibs = categories.get(category);
+                       if (categoryLibs == null) {
+                               categoryLibs = new HashSet<>();
+                               categories.put(category, categoryLibs);
+                       }
+                       categoryLibs.add(name);
+
+                       ArduinoLibrary current = latestLibs.get(name);
+                       if (current != null) {
+                               if (ArduinoPackage.compareVersions(library.getVersion(), current.getVersion()) > 0) {
+                                       latestLibs.put(name, library);
+                               }
+                       } else {
+                               latestLibs.put(name, library);
+                       }
+               }
+       }
+
+       public ArduinoLibrary getLibrary(String name) {
+               return latestLibs.get(name);
+       }
+
+       public Collection<String> getCategories() {
+               return Collections.unmodifiableCollection(categories.keySet());
+       }
+
+       public Collection<ArduinoLibrary> getLibraries(String category) {
+               Set<String> categoryLibs = categories.get(category);
+               if (categoryLibs == null) {
+                       return new ArrayList<>(0);
+               }
+
+               List<ArduinoLibrary> libs = new ArrayList<>(categoryLibs.size());
+               for (String name : categoryLibs) {
+                       libs.add(latestLibs.get(name));
+               }
+               return libs;
+       }
+
+}
index c03c55c..9a1abc9 100644 (file)
@@ -26,7 +26,7 @@ public class PackageIndex {
                return null;
        }
 
-       void setOwners(ArduinoBoardManager manager) {
+       void setOwners(ArduinoManager manager) {
                for (ArduinoPackage pkg : packages) {
                        pkg.setOwner(manager);
                }
index 69e3eb5..68349ae 100644 (file)
@@ -8,6 +8,7 @@ import java.io.InputStreamReader;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -21,7 +22,8 @@ import org.eclipse.cdt.arduino.core.internal.Activator;
 import org.eclipse.cdt.arduino.core.internal.ArduinoPreferences;
 import org.eclipse.cdt.arduino.core.internal.ArduinoTemplateGenerator;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
-import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoardManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoLibrary;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoTool;
@@ -170,7 +172,7 @@ public class ArduinoBuildConfiguration {
                        String packageName = settings.get(PACKAGE_NAME, ""); //$NON-NLS-1$
                        String platformName = settings.get(PLATFORM_NAME, ""); //$NON-NLS-1$
                        String boardName = settings.get(BOARD_NAME, ""); //$NON-NLS-1$
-                       board = ArduinoBoardManager.instance.getBoard(boardName, platformName, packageName);
+                       board = ArduinoManager.instance.getBoard(boardName, platformName, packageName);
                }
                return board;
        }
@@ -184,7 +186,7 @@ public class ArduinoBuildConfiguration {
                        for (ToolDependency toolDep : platform.getToolsDependencies()) {
                                properties.putAll(toolDep.getTool().getToolProperties());
                        }
-                       properties.put("runtime.ide.version", "1.6.7"); //$NON-NLS-1$ //$NON-NLS-2$
+                       properties.put("runtime.ide.version", "10607"); //$NON-NLS-1$ //$NON-NLS-2$
                        properties.put("build.arch", platform.getArchitecture().toUpperCase()); //$NON-NLS-1$
                        properties.put("build.path", config.getName()); //$NON-NLS-1$
                }
@@ -252,6 +254,16 @@ public class ArduinoBuildConfiguration {
                }
                buildModel.put("project_srcs", sourceFiles); //$NON-NLS-1$
 
+               // The list of library sources
+               List<String> librarySources = new ArrayList<>();
+               for (ArduinoLibrary lib : ArduinoManager.instance.getLibraries(project)) {
+                       for (Path path : lib.getSources(project)) {
+                               librarySources.add(path.toString());
+                       }
+               }
+               buildModel.put("libraries_srcs", librarySources); //$NON-NLS-1$
+               buildModel.put("libraries_path", ArduinoPreferences.getArduinoHome().resolve("libraries")); //$NON-NLS-1$ //$NON-NLS-2$
+
                // the recipes
                Properties properties = new Properties();
                properties.putAll(getProperties());
@@ -267,6 +279,11 @@ public class ArduinoBuildConfiguration {
                        }
                        includes += '"' + include.toString() + '"';
                }
+               for (ArduinoLibrary lib : ArduinoManager.instance.getLibraries(project)) {
+                       for (Path include : lib.getIncludePath()) {
+                               includes += " -I\"" + include.toString() + '"'; //$NON-NLS-1$
+                       }
+               }
                properties.put("includes", includes); //$NON-NLS-1$
 
                Path platformPath = platform.getInstallPath();
@@ -290,8 +307,8 @@ public class ArduinoBuildConfiguration {
 
                properties.put("object_file", "$@"); //$NON-NLS-1$ //$NON-NLS-2$
                properties.put("source_file", "$<"); //$NON-NLS-1$ //$NON-NLS-2$
-               properties.put("archive_file", "libc.a"); //$NON-NLS-1$ //$NON-NLS-2$
-               properties.put("object_files", "$(PROJECT_OBJS)"); //$NON-NLS-1$ //$NON-NLS-2$
+               properties.put("archive_file", "core.a"); //$NON-NLS-1$ //$NON-NLS-2$
+               properties.put("object_files", "$(PROJECT_OBJS) $(LIBRARIES_OBJS)"); //$NON-NLS-1$ //$NON-NLS-2$
 
                buildModel.put("recipe_cpp_o_pattern", resolveProperty("recipe.cpp.o.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$
                buildModel.put("recipe_c_o_pattern", resolveProperty("recipe.c.o.pattern", properties)); //$NON-NLS-1$ //$NON-NLS-2$
@@ -442,6 +459,11 @@ public class ArduinoBuildConfiguration {
                }
        }
 
+       public void clearScannerInfoCache() {
+               cppScannerInfo = null;
+               cScannerInfo = null;
+       }
+
        private IScannerInfo calculateScannerInfo(String recipe, IResource resource) throws CoreException {
                try {
                        ArduinoPlatform platform = getBoard().getPlatform();
@@ -456,6 +478,12 @@ public class ArduinoBuildConfiguration {
                        for (Path include : platform.getIncludePath()) {
                                includes += " -I\"" + include.toString() + '"'; //$NON-NLS-1$
                        }
+                       Collection<ArduinoLibrary> libs = ArduinoManager.instance.getLibraries(config.getProject());
+                       for (ArduinoLibrary lib : libs) {
+                               for (Path path : lib.getIncludePath()) {
+                                       includes += " -I\"" + path.toString() + '"'; //$NON-NLS-1$
+                               }
+                       }
                        properties.put("includes", includes); //$NON-NLS-1$
 
                        // TODO Windows
@@ -499,7 +527,7 @@ public class ArduinoBuildConfiguration {
        public ArduinoConsoleParser[] getBuildConsoleParsers() {
                // ../src/Test.cpp:4:1: error: 'x' was not declared in this scope
 
-               return new ArduinoConsoleParser[] { new ArduinoErrorParser("(.*?):(\\d+):(\\d+:)? error: (.*)") { //$NON-NLS-1$
+               return new ArduinoConsoleParser[] { new ArduinoErrorParser("(.*?):(\\d+):(\\d+:)? (fatal )?error: (.*)") { //$NON-NLS-1$
                        @Override
                        protected int getSeverity(Matcher matcher) {
                                return IMarker.SEVERITY_ERROR;
@@ -507,7 +535,7 @@ public class ArduinoBuildConfiguration {
 
                        @Override
                        protected String getMessage(Matcher matcher) {
-                               return matcher.group(4);
+                               return matcher.group(5);
                        }
 
                        @Override
index 088b359..2106c0f 100644 (file)
@@ -16,7 +16,7 @@ import java.util.Map;
 
 import org.eclipse.cdt.arduino.core.internal.Activator;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
-import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoardManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.eclipse.cdt.serial.SerialPort;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.remote.core.IRemoteCommandShellService;
@@ -95,7 +95,7 @@ public class ArduinoRemoteConnection
        }
 
        public ArduinoBoard getBoard() throws CoreException {
-               return ArduinoBoardManager.instance.getBoard(remoteConnection.getAttribute(BOARD_NAME),
+               return ArduinoManager.instance.getBoard(remoteConnection.getAttribute(BOARD_NAME),
                                remoteConnection.getAttribute(PLATFORM_NAME), remoteConnection.getAttribute(PACKAGE_NAME));
        }
 
index 51f22ea..8e9e03d 100644 (file)
@@ -26,6 +26,18 @@ PLATFORM_OBJS = \
 </#if>
 </#list>
 
+LIBRARIES_OBJS = \
+<#list libraries_srcs as file>
+<#assign cpp = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.cpp")>
+<#if cpp>
+       ${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.o \
+</#if>
+<#assign c = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.c")>
+<#if c>
+       ${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.o \
+</#if>
+</#list>  
+
 all: ${build_path}/${project_name}.hex ${build_path}/${project_name}.eep
 
 ${build_path}/${project_name}.hex: ${build_path}/${project_name}.elf
@@ -34,10 +46,10 @@ ${build_path}/${project_name}.hex: ${build_path}/${project_name}.elf
 ${build_path}/${project_name}.eep: ${build_path}/${project_name}.elf
        ${recipe_objcopy_eep_pattern}
 
-${build_path}/${project_name}.elf: $(PROJECT_OBJS) ${build_path}/libc.a
+${build_path}/${project_name}.elf: $(PROJECT_OBJS) $(LIBRARIES_OBJS) ${build_path}/core.a
        ${recipe_c_combine_pattern}
 
-${build_path}/libc.a:  $(PLATFORM_OBJS)
+${build_path}/core.a:  $(PLATFORM_OBJS)
 
 clean:
        $(RMDIR) ${build_path}
@@ -73,3 +85,20 @@ ${build_path}/platform/${c?groups[1]}.o: ${file}
 
 </#if>
 </#list>
+
+<#list libraries_srcs as file>
+<#assign cpp = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.cpp")>
+<#if cpp>
+${build_path}/libraries/${cpp?groups[1]}/${cpp?groups[2]}.o: ${file}
+       @$(call mymkdir,$(dir $@))
+       ${recipe_cpp_o_pattern}
+
+</#if>
+<#assign c = file?matches("${libraries_path}/(.*?)/.*?/(.*)\\.c")>
+<#if c>
+${build_path}/libraries/${c?groups[1]}/${c?groups[2]}.o: ${file}
+       @$(call mymkdir,$(dir $@))
+       ${recipe_c_o_pattern}
+
+</#if>
+</#list>
\ No newline at end of file
index 86ecabd..7971aae 100644 (file)
             </adapt>
          </enabledWhen>
       </page>
+      <page
+            class="org.eclipse.cdt.arduino.ui.internal.project.LibrariesPropertyPage"
+            id="org.eclipse.cdt.arduino.ui.librariesPropertyPage"
+            name="Libraries">
+         <enabledWhen>
+            <and>
+               <instanceof
+                     value="org.eclipse.core.resources.IProject">
+               </instanceof>
+               <test
+                     property="org.eclipse.core.resources.projectNature"
+                     value="org.eclipse.cdt.arduino.core.arduinoNature">
+               </test>
+            </and>
+         </enabledWhen>
+      </page>
    </extension>
    <extension
          point="org.eclipse.launchbar.ui.launchBarUIContributions">
index cfbed04..379ca10 100644 (file)
@@ -15,7 +15,7 @@ import java.util.List;
 import java.util.Set;
 
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
-import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoardManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform;
 import org.eclipse.cdt.arduino.core.internal.board.PackageIndex;
@@ -121,7 +121,7 @@ public class ArduinoBoardsPreferencePage extends PreferencePage implements IWork
                table.removeAll();
 
                try {
-                       PackageIndex packageIndex = ArduinoBoardManager.instance.getPackageIndex();
+                       PackageIndex packageIndex = ArduinoManager.instance.getPackageIndex();
                        List<ArduinoBoard> boards = new ArrayList<>();
                        for (ArduinoPackage pkg : packageIndex.getPackages()) {
                                for (ArduinoPlatform platform : pkg.getLatestPlatforms()) {
diff --git a/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/LibrariesPropertyPage.java b/toolchains/arduino/org.eclipse.cdt.arduino.ui/src/org/eclipse/cdt/arduino/ui/internal/project/LibrariesPropertyPage.java
new file mode 100644 (file)
index 0000000..a579f99
--- /dev/null
@@ -0,0 +1,188 @@
+package org.eclipse.cdt.arduino.ui.internal.project;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoLibrary;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
+import org.eclipse.cdt.arduino.core.internal.board.LibraryIndex;
+import org.eclipse.cdt.arduino.ui.internal.Activator;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
+import org.eclipse.ui.dialogs.FilteredTree;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+public class LibrariesPropertyPage extends PropertyPage {
+
+       private static class ContentProvider implements ITreeContentProvider {
+               private LibraryIndex index;
+
+               @Override
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+                       index = (LibraryIndex) newInput;
+               }
+
+               @Override
+               public void dispose() {
+               }
+
+               @Override
+               public boolean hasChildren(Object element) {
+                       if (element instanceof LibraryIndex) {
+                               return !index.getCategories().isEmpty();
+                       } else if (element instanceof String) { // category
+                               return !index.getLibraries((String) element).isEmpty();
+                       } else if (element instanceof ArduinoLibrary) {
+                               return false;
+                       } else {
+                               return false;
+                       }
+               }
+
+               @Override
+               public Object getParent(Object element) {
+                       if (element instanceof ArduinoLibrary) {
+                               return ((ArduinoLibrary) element).getCategory();
+                       } else if (element instanceof String) {
+                               return index;
+                       } else {
+                               return null;
+                       }
+               }
+
+               @Override
+               public Object[] getElements(Object inputElement) {
+                       return ((LibraryIndex) inputElement).getCategories().toArray(new String[0]);
+               }
+
+               @Override
+               public Object[] getChildren(Object parentElement) {
+                       if (parentElement instanceof String) {
+                               return index.getLibraries((String) parentElement).toArray(new ArduinoLibrary[0]);
+                       } else {
+                               return null;
+                       }
+               }
+       }
+
+       private static class LabelProvider extends BaseLabelProvider implements ITableLabelProvider {
+               @Override
+               public Image getColumnImage(Object element, int columnIndex) {
+                       return null;
+               }
+
+               @Override
+               public String getColumnText(Object element, int columnIndex) {
+                       if (element instanceof String) {
+                               return columnIndex == 0 ? (String) element : null;
+                       } else if (element instanceof ArduinoLibrary) {
+                               switch (columnIndex) {
+                               case 0:
+                                       return ((ArduinoLibrary) element).getName();
+                               case 1:
+                                       return ((ArduinoLibrary) element).getSentence();
+                               default:
+                                       return null;
+                               }
+                       } else {
+                               return null;
+                       }
+               }
+
+       }
+
+       private FilteredTree filteredTree;
+
+       @Override
+       protected Control createContents(Composite parent) {
+               Composite comp = new Composite(parent, SWT.NULL);
+               comp.setLayout(new GridLayout());
+
+               filteredTree = new FilteredTree(comp, SWT.CHECK | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL,
+                               new PatternFilter() {
+                                       @Override
+                                       protected boolean isLeafMatch(Viewer viewer, Object element) {
+                                               if (element instanceof String) {
+                                                       return wordMatches((String) element);
+                                               } else if (element instanceof ArduinoLibrary) {
+                                                       ArduinoLibrary lib = (ArduinoLibrary) element;
+                                                       return wordMatches(lib.getName()) || wordMatches(lib.getSentence())
+                                                                       || wordMatches(lib.getParagraph());
+                                               } else {
+                                                       return false;
+                                               }
+                                       }
+                               }, true) {
+                       @Override
+                       protected TreeViewer doCreateTreeViewer(Composite parent, int style) {
+                               return new ContainerCheckedTreeViewer(parent, style);
+                       }
+               };
+               filteredTree.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+               ContainerCheckedTreeViewer viewer = (ContainerCheckedTreeViewer) filteredTree.getViewer();
+
+               Tree tree = viewer.getTree();
+               tree.setHeaderVisible(true);
+               TreeColumn column1 = new TreeColumn(tree, SWT.LEFT);
+               column1.setText("Name");
+               column1.setWidth(200);
+               TreeColumn column2 = new TreeColumn(tree, SWT.LEFT);
+               column2.setText("Description");
+               column2.setWidth(200);
+
+               viewer.setContentProvider(new ContentProvider());
+               viewer.setLabelProvider(new LabelProvider());
+
+               try {
+                       viewer.setInput(ArduinoManager.instance.getLibraryIndex());
+                       // Set the check states for currently selected libraries
+                       IProject project = getElement().getAdapter(IProject.class);
+                       Collection<ArduinoLibrary> libraries = ArduinoManager.instance.getLibraries(project);
+                       for (ArduinoLibrary lib : libraries) {
+                               viewer.setChecked(lib, true);
+                       }
+               } catch (CoreException e) {
+                       Activator.log(e);
+               }
+
+               return comp;
+       }
+
+       @Override
+       public boolean performOk() {
+               List<ArduinoLibrary> libs = new ArrayList<>();
+               for (TreeItem categoryItem : filteredTree.getViewer().getTree().getItems()) {
+                       for (TreeItem libItem : categoryItem.getItems()) {
+                               ArduinoLibrary lib = (ArduinoLibrary) libItem.getData();
+                               if (libItem.getChecked()) {
+                                       libs.add(lib);
+                               }
+                       }
+               }
+               try {
+                       ArduinoManager.instance.setLibraries(getElement().getAdapter(IProject.class), libs);
+               } catch (CoreException e) {
+                       Activator.log(e);
+               }
+               return true;
+       }
+
+}
index 0e9eae0..ca7f611 100644 (file)
@@ -4,7 +4,7 @@ import java.io.IOException;
 import java.util.Collection;
 
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
-import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoardManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPackage;
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoPlatform;
 import org.eclipse.cdt.arduino.core.internal.remote.ArduinoRemoteConnection;
@@ -76,7 +76,7 @@ public class ArduinoTargetPropertyPage extends PropertyPage implements IWorkbenc
 
                try {
                        ArduinoBoard currentBoard = arduinoRemote.getBoard();
-                       Collection<ArduinoBoard> boardList = ArduinoBoardManager.instance.getBoards();
+                       Collection<ArduinoBoard> boardList = ArduinoManager.instance.getBoards();
                        boards = new ArduinoBoard[boardList.size()];
                        i = 0;
                        int boardSel = 0;
index 2e791ef..756c434 100644 (file)
@@ -6,7 +6,7 @@ import java.util.Comparator;
 import java.util.List;
 
 import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoard;
-import org.eclipse.cdt.arduino.core.internal.board.ArduinoBoardManager;
+import org.eclipse.cdt.arduino.core.internal.board.ArduinoManager;
 import org.eclipse.cdt.arduino.ui.internal.Activator;
 import org.eclipse.cdt.arduino.ui.internal.Messages;
 import org.eclipse.cdt.serial.SerialPort;
@@ -93,7 +93,7 @@ public class NewArduinoTargetWizardPage extends WizardPage {
                boardCombo = new Combo(comp, SWT.READ_ONLY);
                boardCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
                try {
-                       List<ArduinoBoard> boardList = ArduinoBoardManager.instance.getInstalledBoards();
+                       List<ArduinoBoard> boardList = ArduinoManager.instance.getInstalledBoards();
                        Collections.sort(boardList, new Comparator<ArduinoBoard>() {
                                @Override
                                public int compare(ArduinoBoard o1, ArduinoBoard o2) {