Ejemplo n.º 1
0
        public string GenerateBSPForSDK(string directory, IWarningSink sink)
        {
            var bsp = ParseKSDKManifest(directory, sink);

            bsp.Save(directory);

            return(bsp.BSP.PackageID);
        }
Ejemplo n.º 2
0
        public static ParsedSDK ParseKSDKManifest(string sdkDirectory, IWarningSink sink)
        {
            string[] manifestFiles = Directory.GetFiles(sdkDirectory, "*manifest.xml");
            if (manifestFiles.Length < 1)
            {
                throw new Exception($"No manifest files in {sdkDirectory}");
            }

            string manifestFile = Directory.GetFiles(sdkDirectory, "*manifest.xml")[0];

            List <VendorSample> vsl = new List <VendorSample>();

            XmlDocument doc = new XmlDocument();

            doc.Load(manifestFile);

            List <MCU>             mcus          = new List <MCU>();
            List <MCUFamily>       families      = new List <MCUFamily>();
            List <ParsedComponent> allFrameworks = new List <ParsedComponent>();
            bool linkerScriptHandled             = false;

            List <string> allFiles = new List <string>();
            Dictionary <string, ParsedDevice>      deviceDict    = new Dictionary <string, ParsedDevice>();
            Dictionary <string, EmbeddedFramework> frameworkDict = new Dictionary <string, EmbeddedFramework>();
            List <FileCondition> allConditions        = new List <FileCondition>();
            string           fwPrefix                 = "com.sysprogs.ksdk2x_imported.";
            HashSet <string> alwaysIncludedFrameworks = new HashSet <string>();

            foreach (XmlElement devNode in doc.SelectNodes("//devices/device"))
            {
                ParsedDevice dev = new ParsedDevice(devNode, sdkDirectory);

                var mcuFamily = dev.ToMCUFamily();

                int FLASHSize, RAMSize;
                int.TryParse((devNode.SelectSingleNode("memory/@flash_size_kb")?.Value ?? ""), out FLASHSize);
                int.TryParse((devNode.SelectSingleNode("memory/@ram_size_kb")?.Value ?? ""), out RAMSize);
                FLASHSize *= 1024;
                RAMSize   *= 1024;

                families.Add(mcuFamily);
                string svdFile = null;

                //Map each component to an instance of EmbeddedFramework
                foreach (XmlNode componentNode in doc.SelectNodes($"//components/component"))
                {
                    string componentName = componentNode.SelectSingleNode("@name")?.Value ?? "";
                    string componentType = componentNode.SelectSingleNode("@type")?.Value ?? "";
                    string device        = componentNode.SelectSingleNode("@device")?.Value ?? "";

                    switch (componentType)
                    {
                    case "documentation":
                    case "SCR":
                    case "EULA":
                        continue;

                    case "debugger":
                    case "linker":
                    {
                        List <string> relPaths   = new List <string>();
                        bool          isDebug    = componentType == "debugger";
                        string        sourceType = isDebug ? "debug" : "linker";
                        foreach (var src in componentNode.SelectNodes($"source[@type='{sourceType}']").OfType <XmlElement>().Select(e => new ParsedSource(e, dev)))
                        {
                            foreach (var fn in src.AllFiles)
                            {
                                relPaths.Add(fn.RelativePath);
                            }
                        }

                        if (relPaths.Count > 0)
                        {
                            if (isDebug)
                            {
                                svdFile = relPaths[0];
                            }
                            else if (!linkerScriptHandled)
                            {
                                linkerScriptHandled = true;
                                if (relPaths.Count == 1)
                                {
                                    mcuFamily.CompilationFlags.LinkerScript = "$$SYS:BSP_ROOT$$/" + relPaths[0];
                                }
                                else
                                {
                                    const string optionID = "com.sysprogs.imported.ksdk2x.linker_script";
                                    mcuFamily.CompilationFlags.LinkerScript = $"$$SYS:BSP_ROOT$$/$${optionID}$$";
                                    mcuFamily.ConfigurableProperties.PropertyGroups[0].Properties.Add(new PropertyEntry.Enumerated
                                        {
                                            UniqueID       = optionID,
                                            Name           = "Linker script",
                                            AllowFreeEntry = false,
                                            SuggestionList = relPaths.Select(p => new PropertyEntry.Enumerated.Suggestion {
                                                InternalValue = p, UserFriendlyName = Path.GetFileName(p)
                                            }).ToArray()
                                        });
                                }
                            }
                        }
                    }
                        continue;

                    case "CMSIS":
                        //KSDK 2.x defines a Include_xxx framework for each possible CMSIS core. Those frameworks are redundant (normal 'Include' framework references the same include path) and should be removed to avoid confusion.
                        if (componentName.StartsWith("Include_"))
                        {
                            continue;
                        }
                        if (componentName == "Include")
                        {
                            alwaysIncludedFrameworks.Add(fwPrefix + componentName);
                        }
                        break;

                    default:
                        break;
                    }

                    List <string> headerFiles        = new List <string>();
                    List <string> includeDirectories = new List <string>();
                    List <string> sourceFiles        = new List <string>();

                    foreach (ParsedSource src in componentNode.SelectNodes("source").OfType <XmlElement>().Select(e => new ParsedSource(e, dev)))
                    {
                        if (src.Type == "c_include")
                        {
                            includeDirectories.Add(src.BSPPath);
                        }

                        foreach (var file in src.AllFiles)
                        {
                            if (src.Type == "src" || src.Type == "asm_include")
                            {
                                sourceFiles.Add(file.BSPPath);
                            }
                            else if (src.Type == "c_include")
                            {
                                headerFiles.Add(file.BSPPath);
                            }
                        }
                    }

                    if (componentName == "clock" && componentType == "driver")
                    {
                        alwaysIncludedFrameworks.Add(fwPrefix + componentName);
                    }

                    string[] dependencyList = componentNode.Attributes?.GetNamedItem("dependency")?.Value?.Split(' ')
                                              ?.Select(id => fwPrefix + id)
                                              ?.ToArray() ?? new string[0];

                    EmbeddedFramework fw = new EmbeddedFramework
                    {
                        ID = $"{fwPrefix}{componentName}",
                        UserFriendlyName             = $"{componentName} ({componentType})",
                        ProjectFolderName            = componentName,
                        AdditionalSourceFiles        = sourceFiles.Distinct().ToArray(),
                        AdditionalHeaderFiles        = headerFiles.Distinct().ToArray(),
                        RequiredFrameworks           = dependencyList,
                        AdditionalIncludeDirs        = includeDirectories.Distinct().ToArray(),
                        AdditionalPreprocessorMacros = componentNode.SelectNodes("defines/define").OfType <XmlElement>().Select(el => new ParsedDefine(el).Definition).ToArray(),
                    };

                    if (componentName == "freertos" && componentType == "OS")
                    {
                        fw.AdditionalPreprocessorMacros = LoadedBSP.Combine(fw.AdditionalPreprocessorMacros, "USE_RTOS=1;USE_FREERTOS".Split(';'));
                        fw.ConfigurableProperties       = new PropertyList
                        {
                            PropertyGroups = new List <PropertyGroup>()
                            {
                                new PropertyGroup
                                {
                                    Properties = new List <PropertyEntry>()
                                    {
                                        new PropertyEntry.Enumerated
                                        {
                                            Name              = "FreeRTOS Heap Implementation",
                                            UniqueID          = "com.sysprogs.bspoptions.stm32.freertos.heap",
                                            DefaultEntryIndex = 3,
                                            SuggestionList    = new PropertyEntry.Enumerated.Suggestion[]
                                            {
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_1", UserFriendlyName = "Heap1 - no support for freeing"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_2", UserFriendlyName = "Heap2 - no block consolidation"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_3", UserFriendlyName = "Heap3 - use newlib malloc()/free()"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_4", UserFriendlyName = "Heap4 - contiguous heap area"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_5", UserFriendlyName = "Heap5 - scattered heap area"
                                                },
                                            }
                                        }
                                    }
                                }
                            }
                        };

                        foreach (var fn in fw.AdditionalSourceFiles)
                        {
                            string name = Path.GetFileName(fn);
                            if (name.StartsWith("heap_"))
                            {
                                allConditions.Add(new FileCondition {
                                    FilePath = fn, ConditionToInclude = new Condition.Equals {
                                        Expression = "$$com.sysprogs.bspoptions.stm32.freertos.heap$$", ExpectedValue = Path.GetFileNameWithoutExtension(fn)
                                    }
                                });
                            }
                        }
                    }

                    if (frameworkDict.ContainsKey(fw.ID))
                    {
                        sink.LogWarning("Duplicate framework for " + fw.ID);
                        continue;
                    }

                    frameworkDict[fw.ID] = fw;

                    if (string.IsNullOrEmpty(fw.ID))
                    {
                        sink.LogWarning($"Found a framework with empty ID. Skipping...");
                        continue;
                    }

                    if (string.IsNullOrEmpty(fw.UserFriendlyName))
                    {
                        fw.UserFriendlyName = fw.ID;
                    }

                    allFrameworks.Add(new ParsedComponent {
                        Framework = fw, OriginalType = componentType, OriginalName = componentName
                    });
                    allFiles.AddRange(sourceFiles);
                    allFiles.AddRange(headerFiles);
                }

                string deviceDefinitionFile = null;
                if (svdFile != null)
                {
                    try
                    {
                        var mcuDef = SVDParser.ParseSVDFile(Path.Combine(sdkDirectory, svdFile), dev.DeviceName);
                        deviceDefinitionFile = Path.ChangeExtension(svdFile, ".vgdbdevice");

                        XmlSerializer ser = new XmlSerializer(typeof(MCUDefinition));
                        using (var fs = File.Create(Path.Combine(sdkDirectory, Path.ChangeExtension(svdFile, ".vgdbdevice.gz"))))
                            using (var gs = new GZipStream(fs, CompressionMode.Compress, true))
                                ser.Serialize(gs, new MCUDefinition(mcuDef));
                    }
                    catch (Exception ex)
                    {
                        sink.LogWarning($"Failed to parse {svdFile}: {ex.Message}");
                    }
                }

                foreach (XmlNode packageNode in devNode.SelectNodes($"package/@name"))
                {
                    string pkgName = packageNode?.Value;
                    if (string.IsNullOrEmpty(pkgName))
                    {
                        continue;
                    }

                    deviceDict[pkgName] = dev;

                    mcus.Add(new MCU
                    {
                        ID = pkgName,
                        UserFriendlyName = $"{pkgName} (KSDK 2.x)",
                        FamilyID         = mcuFamily.ID,
                        FLASHSize        = FLASHSize,
                        RAMSize          = RAMSize,
                        CompilationFlags = new ToolFlags
                        {
                            PreprocessorMacros = new string[] { "CPU_" + pkgName }
                        },

                        MCUDefinitionFile = deviceDefinitionFile
                    });
                }
            }

            if (families.Count == 0)
            {
                throw new Exception("The selected KSDK contains no families");
            }

            List <VendorSample> samples = new List <VendorSample>();

            foreach (XmlElement boardNode in doc.SelectNodes("//boards/board"))
            {
                string       boardName = boardNode.GetAttribute("name");
                string       deviceID  = boardNode.GetAttribute("package");
                ParsedDevice dev;
                if (!deviceDict.TryGetValue(deviceID, out dev))
                {
                    continue;
                }

                foreach (XmlElement exampleNode in boardNode.SelectNodes("examples/example"))
                {
                    List <string> dependencyList = new List <string>(exampleNode.Attributes?.GetNamedItem("dependency")?.Value?.Split(' ')
                                                                     ?.Select(id => fwPrefix + id) ?? new string[0]);

                    dependencyList.AddRange(alwaysIncludedFrameworks);

                    for (int i = 0; i < dependencyList.Count; i++)
                    {
                        EmbeddedFramework fw;
                        if (frameworkDict.TryGetValue(dependencyList[i], out fw) && fw?.RequiredFrameworks != null)
                        {
                            dependencyList.AddRange(fw.RequiredFrameworks.Except(dependencyList));
                        }
                    }

                    VendorSample sample = new VendorSample
                    {
                        DeviceID         = deviceID,
                        UserFriendlyName = exampleNode.GetAttribute("name") ?? "???",
                        BoardName        = boardName,
                        Configuration    = new VendorSampleConfiguration
                        {
                            Frameworks = dependencyList.ToArray()
                        },
                        VirtualPath    = exampleNode.GetAttribute("category"),
                        NoImplicitCopy = true
                    };

                    List <string> headerFiles        = new List <string>();
                    List <string> includeDirectories = new List <string>();
                    List <string> sourceFiles        = new List <string>();

                    foreach (var src in exampleNode.SelectNodes("source").OfType <XmlElement>().Select(e => new ParsedSource(e, dev)))
                    {
                        foreach (var file in src.AllFiles)
                        {
                            if (src.Type == "src" || src.Type == "asm_include")
                            {
                                sourceFiles.Add(file.BSPPath);
                            }
                            else if (src.Type == "c_include")
                            {
                                headerFiles.Add(file.BSPPath);
                            }
                        }
                    }

                    sample.SourceFiles = sourceFiles.ToArray();
                    sample.HeaderFiles = headerFiles.ToArray();

                    if (sourceFiles.Count == 0 && headerFiles.Count == 0)
                    {
                        continue;
                    }

                    string[] matchingComponents = null;

                    foreach (var fn in sourceFiles.Concat(headerFiles))
                    {
                        string[] components = fn.Split('/', '\\');
                        if (matchingComponents == null)
                        {
                            matchingComponents = components;
                        }
                        else
                        {
                            int matches = CountMatches(matchingComponents, components);
                            if (matches < matchingComponents.Length)
                            {
                                Array.Resize(ref matchingComponents, matches);
                            }
                        }
                    }

                    if (matchingComponents != null)
                    {
                        sample.Path = string.Join("/", matchingComponents);
                    }

                    samples.Add(sample);
                }
            }


            return(new ParsedSDK
            {
                BSP = new BoardSupportPackage
                {
                    PackageID = "com.sysprogs.imported.ksdk2x." + families[0].ID,
                    PackageDescription = "Imported KSDK 2.x for " + families[0].ID,
                    PackageVersion = doc.SelectSingleNode("//ksdk/@version")?.Value ?? "unknown",
                    GNUTargetID = "arm-eabi",
                    Frameworks = allFrameworks.Where(f => f.OriginalType != "project_template").Select(f => f.Framework).ToArray(),
                    MCUFamilies = families.ToArray(),
                    SupportedMCUs = mcus.ToArray(),
                    FileConditions = allFiles
                                     .Where(f => f.IndexOf("freertos", StringComparison.InvariantCultureIgnoreCase) != -1)
                                     .Select(f => new FileCondition {
                        FilePath = f, ConditionToInclude = new Condition.ReferencesFramework {
                            FrameworkID = fwPrefix + "freertos"
                        }
                    })
                                     .Concat(allConditions)
                                     .ToArray(),
                    VendorSampleCatalogName = "KSDK Samples",
                    EmbeddedSamples = allFrameworks.Where(f => f.OriginalType == "project_template").Select(f => f.ToProjectSample(alwaysIncludedFrameworks)).ToArray(),
                },

                VendorSampleDirectory = new VendorSampleDirectory
                {
                    Samples = samples.ToArray()
                }
            });
        }
Ejemplo n.º 3
0
        public static ParsedSDK ParseKSDKManifest(string sdkDirectory, IWarningSink sink)
        {
            string[] manifestFiles = Directory.GetFiles(sdkDirectory, "*manifest.xml");
            if (manifestFiles.Length < 1)
            {
                throw new Exception($"No manifest files in {sdkDirectory}");
            }

            string manifestFile = Directory.GetFiles(sdkDirectory, "*manifest.xml")[0];

            List <VendorSample> vsl = new List <VendorSample>();

            XmlDocument doc = new XmlDocument();

            doc.Load(manifestFile);

            List <MCU>             mcus          = new List <MCU>();
            List <MCUFamily>       families      = new List <MCUFamily>();
            List <ParsedComponent> allFrameworks = new List <ParsedComponent>();
            bool linkerScriptHandled             = false;

            List <string> allFiles = new List <string>();
            Dictionary <string, ParsedDevice>      deviceDict    = new Dictionary <string, ParsedDevice>();
            Dictionary <string, EmbeddedFramework> frameworkDict = new Dictionary <string, EmbeddedFramework>();
            List <FileCondition> allConditions        = new List <FileCondition>();
            string           fwPrefix                 = "com.sysprogs.ksdk2x_imported.";
            HashSet <string> alwaysIncludedFrameworks = new HashSet <string>();
            // HashSet<string> alwaysExcludedFrameworks = new HashSet<string>();
            List <string>     lstdevAll = new List <string>();
            List <CopiedFile> cfs       = new List <CopiedFile>();
            var dictCopiedFile          = new ListDictionary <string, CopiedFile>();
            var dictAddIncludeDir       = new ListDictionary <string, string>();


            foreach (XmlElement devNode in doc.SelectNodes("//devices/device"))
            {
                lstdevAll.Add(new ParsedDevice(devNode, sdkDirectory).DeviceName);
            }

            foreach (XmlElement devNode in doc.SelectNodes("//devices/device"))
            {
                ParsedDevice dev = new ParsedDevice(devNode, sdkDirectory);

                var mcuFamily = dev.ToMCUFamily();

                int FLASHSize, RAMSize;
                int.TryParse((devNode.SelectSingleNode("memory/@flash_size_kb")?.Value ?? ""), out FLASHSize);
                int.TryParse((devNode.SelectSingleNode("memory/@ram_size_kb")?.Value ?? ""), out RAMSize);
                FLASHSize *= 1024;
                RAMSize   *= 1024;

                families.Add(mcuFamily);
                string svdFile = null;

                //Map each component to an instance of EmbeddedFramework
                foreach (XmlNode componentNode in doc.SelectNodes($"//components/component"))
                {
                    string componentName = componentNode.SelectSingleNode("@name")?.Value ?? "";
                    string componentType = componentNode.SelectSingleNode("@type")?.Value ?? "";
                    string device        = componentNode.SelectSingleNode("@device")?.Value ?? "";
                    string idComponent   = componentNode.SelectSingleNode("@id")?.Value ?? "";
                    device = idComponent.Split('.').Last();

                    if (device != dev.DeviceName && (lstdevAll.Contains(device)))
                    {
                        continue;
                    }
                    switch (componentType)
                    {
                    case "documentation":
                    case "SCR":
                    case "EULA":
                        continue;

                    case "debugger":
                    case "linker":
                    {
                        List <string> relPaths   = new List <string>();
                        bool          isDebug    = componentType == "debugger";
                        string        sourceType = isDebug ? "debug" : "linker";
                        foreach (var src in componentNode.SelectNodes($"source[@type='{sourceType}' and @toolchain='armgcc']").OfType <XmlElement>().Select(e => new ParsedSource(e, dev)))
                        {
                            foreach (var fn in src.AllFiles)
                            {
                                relPaths.Add(fn.RelativePath);
                            }
                        }

                        if (relPaths.Count > 0)
                        {
                            if (isDebug)
                            {
                                svdFile = relPaths[0];
                            }
                            else if (!linkerScriptHandled)
                            {
                                linkerScriptHandled = true;
                                if (relPaths.Count == 1)
                                {
                                    mcuFamily.CompilationFlags.LinkerScript = "$$SYS:BSP_ROOT$$/" + relPaths[0];
                                }
                                else
                                {
                                    const string optionID = "com.sysprogs.imported.ksdk2x.linker_script";
                                    mcuFamily.CompilationFlags.LinkerScript = $"$$SYS:BSP_ROOT$$/$${optionID}$$";
                                    if ((mcuFamily.ConfigurableProperties?.PropertyGroups?.Count ?? 0) == 0)
                                    {
                                        mcuFamily.ConfigurableProperties = new PropertyList {
                                            PropertyGroups = new List <PropertyGroup> {
                                                new PropertyGroup()
                                            }
                                        }
                                    }
                                    ;

                                    mcuFamily.ConfigurableProperties.PropertyGroups[0].Properties.Add(new PropertyEntry.Enumerated
                                        {
                                            UniqueID       = optionID,
                                            Name           = "Linker script",
                                            AllowFreeEntry = false,
                                            SuggestionList = relPaths.Select(p => new PropertyEntry.Enumerated.Suggestion {
                                                InternalValue = p, UserFriendlyName = Path.GetFileName(p)
                                            }).ToArray()
                                        });
                                }
                            }
                        }
                    }
                        continue;

                    case "CMSIS":

                        //KSDK 2.x defines a Include_xxx framework for each possible CMSIS core. Those frameworks are redundant (normal 'Include' framework references the same include path) and should be removed to avoid confusion.
                        if (componentName.StartsWith("Include_"))
                        {
                            continue;
                        }
                        if (idComponent == "platform.CMSIS_Driver")
                        {
                            continue;
                        }

                        if (componentName == "Include")
                        {
                            alwaysIncludedFrameworks.Add(fwPrefix + componentName);    //!!! +"."+dev.DeviceName);
                        }
                        if (idComponent == "platform.CMSIS")
                        {
                            alwaysIncludedFrameworks.Add(fwPrefix + idComponent);    //!!! + "." + dev.DeviceName);
                        }
                        break;

                    case "project_template":
                        continue;

                    default:
                        break;
                    }

                    List <string> headerFiles        = new List <string>();
                    List <string> includeDirectories = new List <string>();
                    List <string> sourceFiles        = new List <string>();
                    List <string> libFiles           = new List <string>();

                    var IDFr = fwPrefix + idComponent;

                    foreach (ParsedSource src in componentNode.SelectNodes("source").OfType <XmlElement>().Select(e => new ParsedSource(e, dev)))
                    {
                        if (src.Exclude)
                        {
                            continue;
                        }

                        if (src.Type == "c_include")
                        {
                            includeDirectories.Add(src.BSPPath);
                        }

                        foreach (var file in src.AllFiles)
                        {
                            if (file.BSPPath.EndsWith("ucosii.c") && !componentName.Contains("ucosii"))
                            {
                                continue;
                            }
                            if (file.BSPPath.EndsWith("ucosiii.c") && !componentName.Contains("ucosiii"))
                            {
                                continue;
                            }

                            if (file.BSPPath.Contains("freertos"))
                            {
                                allConditions.Add(new FileCondition
                                {
                                    FilePath           = file.BSPPath,
                                    ConditionToInclude = new Condition.ReferencesFramework
                                    {
                                        FrameworkID = fwPrefix + "middleware.freertos." + dev.DeviceName
                                    }
                                });
                            }

                            if (src.TargetPath != "")
                            {
                                dictCopiedFile.Add(IDFr, new CopiedFile {
                                    SourcePath = file.BSPPath, TargetPath = src.TargetPath + "/" + Path.GetFileName(file.BSPPath)
                                });
                                foreach (XmlElement patch in componentNode.SelectNodes("include_paths/include_path"))
                                {
                                    dictAddIncludeDir.Add(IDFr, patch.GetAttribute("path"));
                                }
                            }
                            if (src.Type == "lib")
                            {
                                libFiles.Add(file.BSPPath);
                            }

                            if (src.Type == "src" || src.Type == "asm_include")
                            {
                                sourceFiles.Add(file.BSPPath);
                            }
                            else if (src.Type == "c_include")
                            {
                                headerFiles.Add(file.BSPPath);
                            }
                        }
                    }

                    foreach (XmlElement patch in componentNode.SelectNodes("include_paths/include_path"))
                    {
                        includeDirectories.Add(patch.GetAttribute("path"));
                    }

                    string[] dependencyList = componentNode.Attributes?.GetNamedItem("dependency")?.Value?.Split(' ')
                                              ?.Select(id => fwPrefix + id)
                                              ?.ToArray() ?? new string[0];

                    var FilterRegex = device.Length > 5 ? $"^{device.Substring(0, 5)}.*" : $"^{device}.*"; //MK02F MK22F
                    if (device.Length == 0)
                    {
                        FilterRegex = "";
                    }

                    EmbeddedFramework fw = new EmbeddedFramework
                    {
                        ID                           = $"{IDFr}",
                        MCUFilterRegex               = FilterRegex,
                        UserFriendlyName             = $"{componentName} ({componentType})",
                        ProjectFolderName            = componentName,
                        AdditionalSourceFiles        = sourceFiles.Distinct().ToArray(),
                        AdditionalHeaderFiles        = headerFiles.Distinct().ToArray(),
                        RequiredFrameworks           = dependencyList,
                        AdditionalIncludeDirs        = includeDirectories.Distinct().ToArray(),
                        AdditionalLibraries          = libFiles.ToArray(),
                        AdditionalPreprocessorMacros = componentNode.SelectNodes("defines/define").OfType <XmlElement>().Select(el => new ParsedDefine(el).Definition).ToArray(),
                    };

                    if (componentName == "freertos" && componentType == "OS")
                    {
                        fw.AdditionalPreprocessorMacros = LoadedBSP.Combine(fw.AdditionalPreprocessorMacros, "USE_RTOS=1;USE_FREERTOS".Split(';'));
                        fw.ConfigurableProperties       = new PropertyList
                        {
                            PropertyGroups = new List <PropertyGroup>()
                            {
                                new PropertyGroup
                                {
                                    Properties = new List <PropertyEntry>()
                                    {
                                        new PropertyEntry.Enumerated
                                        {
                                            Name              = "FreeRTOS Heap Implementation",
                                            UniqueID          = "com.sysprogs.bspoptions.stm32.freertos.heap",
                                            DefaultEntryIndex = 3,
                                            SuggestionList    = new PropertyEntry.Enumerated.Suggestion[]
                                            {
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_1", UserFriendlyName = "Heap1 - no support for freeing"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_2", UserFriendlyName = "Heap2 - no block consolidation"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_3", UserFriendlyName = "Heap3 - use newlib malloc()/free()"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_4", UserFriendlyName = "Heap4 - contiguous heap area"
                                                },
                                                new PropertyEntry.Enumerated.Suggestion {
                                                    InternalValue = "heap_5", UserFriendlyName = "Heap5 - scattered heap area"
                                                },
                                            }
                                        }
                                    }
                                }
                            }
                        };

                        foreach (var fn in fw.AdditionalSourceFiles)
                        {
                            string name = Path.GetFileName(fn);
                            if (name.StartsWith("heap_"))
                            {
                                allConditions.Add(new FileCondition {
                                    FilePath = fn, ConditionToInclude = new Condition.Equals {
                                        Expression = "$$com.sysprogs.bspoptions.stm32.freertos.heap$$", ExpectedValue = Path.GetFileNameWithoutExtension(fn)
                                    }
                                });
                            }
                        }
                    }

                    if (frameworkDict.ContainsKey(fw.ID))
                    {
                        sink.LogWarning("Duplicate framework for " + fw.ID);
                        continue;
                    }

                    frameworkDict[fw.ID] = fw;

                    if (string.IsNullOrEmpty(fw.ID))
                    {
                        sink.LogWarning($"Found a framework with empty ID. Skipping...");
                        continue;
                    }

                    if (string.IsNullOrEmpty(fw.UserFriendlyName))
                    {
                        fw.UserFriendlyName = fw.ID;
                    }

                    allFrameworks.Add(new ParsedComponent {
                        Framework = fw, OriginalType = componentType, OriginalName = componentName
                    });
                    allFiles.AddRange(sourceFiles);
                    allFiles.AddRange(headerFiles);
                }

                string deviceDefinitionFile = null;
                if (svdFile != null)
                {
                    try
                    {
                        var mcuDef = SVDParser.ParseSVDFile(Path.Combine(sdkDirectory, svdFile), dev.DeviceName);
                        deviceDefinitionFile = Path.ChangeExtension(svdFile, ".vgdbdevice");

                        XmlSerializer ser = new XmlSerializer(typeof(MCUDefinition));
                        using (var fs = File.Create(Path.Combine(sdkDirectory, Path.ChangeExtension(svdFile, ".vgdbdevice.gz"))))
                            using (var gs = new GZipStream(fs, CompressionMode.Compress, true))
                                ser.Serialize(gs, new MCUDefinition(mcuDef));
                    }
                    catch (Exception ex)
                    {
                        sink.LogWarning($"Failed to parse {svdFile}: {ex.Message}");
                    }
                }

                foreach (XmlNode packageNode in devNode.SelectNodes($"package/@name"))
                {
                    string pkgName = packageNode?.Value;
                    if (string.IsNullOrEmpty(pkgName))
                    {
                        continue;
                    }

                    deviceDict[pkgName] = dev;

                    mcus.Add(new MCU
                    {
                        ID = pkgName,
                        UserFriendlyName = $"{pkgName} (KSDK 2.x)",
                        FamilyID         = mcuFamily.ID,
                        FLASHSize        = FLASHSize,
                        RAMSize          = RAMSize,
                        CompilationFlags = new ToolFlags
                        {
                            PreprocessorMacros = new string[] { "CPU_" + pkgName },
                        },

                        MCUDefinitionFile = deviceDefinitionFile
                    });
                }
            }

            if (families.Count == 0)
            {
                throw new Exception("The selected KSDK contains no families");
            }

            List <VendorSample> samples = new List <VendorSample>();

            foreach (XmlElement boardNode in doc.SelectNodes("//boards/board"))
            {
                string       boardName = boardNode.GetAttribute("name");
                string       deviceID  = boardNode.GetAttribute("package");
                ParsedDevice dev;
                if (!deviceDict.TryGetValue(deviceID, out dev))
                {
                    continue;
                }

                foreach (XmlElement directExampleNode in boardNode.SelectNodes("examples/example"))
                {
                    var exampleNode = directExampleNode;

                    var externalNode = exampleNode.SelectSingleNode("external/files");
                    if (externalNode != null)
                    {
                        var path = (externalNode.ParentNode as XmlElement)?.GetAttribute("path");
                        var mask = (externalNode as XmlElement)?.GetAttribute("mask");
                        if (path != null && mask != null)
                        {
                            {
                                var sampleFiles = Directory.GetFiles(Path.Combine(sdkDirectory, path), mask);
                                var fn          = sampleFiles?.FirstOrDefault();
                                if (fn != null)
                                {
                                    XmlDocument doc2 = new XmlDocument();
                                    doc2.Load(fn);
                                    exampleNode = doc2.DocumentElement.SelectSingleNode("example") as XmlElement;
                                    if (exampleNode == null)
                                    {
                                        continue;
                                    }
                                }
                            }
                        }
                    }

                    List <string> dependencyList = new List <string>(exampleNode.Attributes?.GetNamedItem("dependency")?.Value?.Split(' ')
                                                                     ?.Select(id => fwPrefix + id) ?? new string[0]);

                    var name = exampleNode.GetAttribute("id") ?? "???";

                    dependencyList.AddRange(alwaysIncludedFrameworks);

                    for (int i = 0; i < dependencyList.Count; i++)
                    {
                        EmbeddedFramework fw;
                        if (frameworkDict.TryGetValue(dependencyList[i], out fw) && fw?.RequiredFrameworks != null)
                        {
                            dependencyList.AddRange(fw.RequiredFrameworks.Except(dependencyList));
                        }
                    }
                    List <string>     dependencyList1     = new List <string>(dependencyList.Distinct());
                    List <CopiedFile> CopiedFileForSample = new List <CopiedFile>();
                    List <string>     includeDirectories  = new List <string>();
                    foreach (var fr1 in dependencyList1)
                    {
                        if (!dictCopiedFile.ContainsKey(fr1))
                        {
                            continue;
                        }

                        var l = dictCopiedFile[fr1];
                        CopiedFileForSample.AddRange(l);
                        if (dictAddIncludeDir.ContainsKey(fr1))
                        {
                            includeDirectories.AddRange(dictAddIncludeDir[fr1]);
                        }
                    }
                    List <PropertyDictionary2.KeyValue> CfgEntr = new List <PropertyDictionary2.KeyValue>();

                    string typFpu = "soft";
                    var    tth    = exampleNode.SelectSingleNode("toolchainSettings/toolchainSetting/option[@id='com.crt.advproject.gcc.fpu']")?.InnerText ?? "soft";

                    if (tth.Contains("hard"))
                    {
                        typFpu = "hard";
                    }

                    CfgEntr.Add(new PropertyDictionary2.KeyValue
                    {
                        Key   = "com.sysprogs.bspoptions.arm.floatmode",
                        Value = "-mfloat-abi=" + typFpu
                    });


                    VendorSample sample = new VendorSample
                    {
                        DeviceID         = deviceID,
                        UserFriendlyName = name,
                        BoardName        = boardName,
                        Configuration    = new VendorSampleConfiguration
                        {
                            Frameworks       = dependencyList.Distinct().ToArray(),
                            MCUConfiguration = new PropertyDictionary2 {
                                Entries = CfgEntr.ToArray()
                            }
                        },
                        VirtualPath = exampleNode.GetAttribute("category"),
                        ExtraFiles  = CopiedFileForSample.Distinct().ToArray(),

                        NoImplicitCopy = true
                    };

                    List <string> headerFiles = new List <string>();

                    List <string> sourceFiles = new List <string>();
                    foreach (var cf in CopiedFileForSample.Distinct())
                    {
                        includeDirectories.Add(Path.GetDirectoryName(cf.TargetPath));
                    }


                    foreach (var src in exampleNode.SelectNodes("source").OfType <XmlElement>().Select(e => new ParsedSource(e, dev)))
                    {
                        foreach (var file in src.AllFiles)
                        {
                            if (src.Type == "src" || src.Type == "asm_include")
                            {
                                sourceFiles.Add(file.BSPPath);
                            }
                            else if (src.Type == "c_include")
                            {
                                headerFiles.Add(file.BSPPath);
                            }
                            if (src.Type == "lib")
                            {
                                sourceFiles.Add(file.BSPPath);
                            }
                        }
                    }

                    sample.PreprocessorMacros = exampleNode.SelectNodes("toolchainSettings/toolchainSetting/option[@id='gnu.c.compiler.option.preprocessor.def.symbols']/value").OfType <XmlElement>().
                                                Select(node => node.InnerText.Replace("'\"", "'<").Replace("\"'", ">'")).ToArray();

                    sample.SourceFiles = sourceFiles.ToArray();
                    sample.HeaderFiles = headerFiles.ToArray();

                    if (sourceFiles.Count == 0 && headerFiles.Count == 0)
                    {
                        continue;
                    }

                    string[] matchingComponents = null;

                    foreach (var fn in sourceFiles.Concat(headerFiles))
                    {
                        string[] components = fn.Split('/', '\\');
                        if (matchingComponents == null)
                        {
                            matchingComponents = components;
                        }
                        else
                        {
                            int matches = CountMatches(matchingComponents, components);
                            if (matches < matchingComponents.Length)
                            {
                                Array.Resize(ref matchingComponents, matches);
                            }
                        }
                    }

                    if (matchingComponents != null)
                    {
                        sample.Path = string.Join("/", matchingComponents);
                    }

                    foreach (var hf in headerFiles)
                    {
                        int c = hf.LastIndexOf('/');
                        includeDirectories.Add(hf.Substring(0, c));
                    }

                    sample.IncludeDirectories = includeDirectories.Distinct().ToArray();
                    samples.Add(sample);
                }
            }

            return(new ParsedSDK
            {
                BSP = new BoardSupportPackage
                {
                    PackageID = "com.sysprogs.imported.ksdk2x." + families[0].ID,
                    PackageDescription = "Imported KSDK 2.x for " + families[0].ID,
                    PackageVersion = doc.SelectSingleNode("//ksdk/@version")?.Value ?? "unknown",
                    GNUTargetID = "arm-eabi",
                    Frameworks = allFrameworks.Where(f => f.OriginalType != "project_template").Select(f => f.Framework).ToArray(),
                    MCUFamilies = families.ToArray(),
                    SupportedMCUs = mcus.ToArray(),
                    FileConditions = allConditions.ToArray(),
                    VendorSampleCatalogName = "KSDK Samples",
                    EmbeddedSamples = allFrameworks.Where(f => f.OriginalType == "project_template").Select(f => f.ToProjectSample(alwaysIncludedFrameworks)).ToArray(),
                },

                VendorSampleDirectory = new VendorSampleDirectory
                {
                    Samples = samples.ToArray()
                }
            });
        }
Ejemplo n.º 4
0
        public static BoardSupportPackage GenerateBSPForSTARTProject(string extractedProjectDirectory, IWarningSink sink)
        {
            var gpdscFile = Path.Combine(extractedProjectDirectory, "AtmelStart.gpdsc");

            if (!File.Exists(gpdscFile))
            {
                throw new Exception($"{gpdscFile} does not exist!");
            }

            var gccMakefile = Path.Combine(extractedProjectDirectory, "gcc\\Makefile");

            if (!File.Exists(gccMakefile))
            {
                throw new Exception($"{gccMakefile} does not exist. {GCCExportHint}");
            }

            var xml = new XmlDocument();

            xml.Load(gpdscFile);
            string device = null;

            foreach (var node in xml.SelectNodes("package/generators/generator/select").OfType <XmlElement>())
            {
                var name   = node.GetAttribute("Dname");
                var vendor = node.GetAttribute("Dvendor");
                if (!string.IsNullOrEmpty(vendor) && !string.IsNullOrEmpty(name))
                {
                    device = name;
                }
            }

            if (device == null)
            {
                throw new Exception($"Could not find the device ID in {gpdscFile}");
            }

            var linkerScripts = DetectLinkerScripts(extractedProjectDirectory);
            var memories      = ScanLinkerScriptForMemories(Path.Combine(extractedProjectDirectory, linkerScripts.RelativeFLASHScript));

            var flagsFromMakefile = ScanMakefileForCommonFlags(gccMakefile);

            var mcu = new MCU
            {
                ID       = device,
                FamilyID = "ATSTART",

                FLASHBase = (uint)(memories.FirstOrDefault(m => m.Name == "rom")?.Address ?? uint.MaxValue),
                FLASHSize = (int)(memories.FirstOrDefault(m => m.Name == "rom")?.Size ?? uint.MaxValue),

                RAMBase = (uint)(memories.FirstOrDefault(m => m.Name == "ram")?.Address ?? uint.MaxValue),
                RAMSize = (int)(memories.FirstOrDefault(m => m.Name == "ram")?.Size ?? uint.MaxValue),

                CompilationFlags = new ToolFlags
                {
                    PreprocessorMacros = new[] { $"__{device}__" },
                    COMMONFLAGS        = string.Join(" ", flagsFromMakefile.CommonFlags),
                    LinkerScript       = linkerScripts.LinkerScriptFormat,
                    IncludeDirectories = flagsFromMakefile.RelativeIncludeDirs?.Select(d => "$$SYS:BSP_ROOT$$/" + d).ToArray(),
                    LDFLAGS            = "-Wl,--entry=Reset_Handler", //Unless this is specified explicitly, the gdb's "load" command won't set $pc to the entry point, requiring an explicit device reset.
                },

                ConfigurableProperties = new PropertyList
                {
                    PropertyGroups = new[] { linkerScripts.ToPropertyGroup() }.Where(g => g != null).ToList()
                },

                MemoryMap = new AdvancedMemoryMap
                {
                    Memories = memories.ToArray()
                }
            };

            var bsp = new BoardSupportPackage
            {
                PackageID          = "com.sysprogs.atstart." + device,
                GNUTargetID        = "arm-eabi",
                PackageDescription = $"{device} Support",
                MCUFamilies        = new[] { new MCUFamily {
                                                 ID = "ATSTART"
                                             } },
                SupportedMCUs = new[] { mcu },
                Frameworks    = xml.SelectNodes("package/components/component").OfType <XmlElement>().Select(GenerateFrameworkForComponent).Where(f => f != null).ToArray(),

                EmbeddedSamples = new[]
                {
                    new EmbeddedProjectSample
                    {
                        Name                    = "Default Project",
                        Description             = "A basic project generated by Atmel START",
                        AdditionalSourcesToCopy = new[]
                        {
                            new AdditionalSourceFile
                            {
                                SourcePath     = "$$SYS:BSP_ROOT$$/main.c",
                                TargetFileName = "$$PROJECTNAME$$.c",
                            }
                        }
                    }
                }
            };

            FixGPDSCErrors(bsp, mcu, extractedProjectDirectory, flagsFromMakefile, linkerScripts.RelativeFLASHScript);

            XmlTools.SaveObject(bsp, Path.Combine(extractedProjectDirectory, LoadedBSP.PackageFileName));
            return(bsp);
        }
Ejemplo n.º 5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="extractedProjectDirectory"></param>
        /// <param name="sink"></param>
        /// <returns></returns>
        public static BoardSupportPackage GenerateBSPForSTARTProject(string extractedProjectDirectory, IWarningSink sink)
        {
            var gpdscFile = Path.Combine(extractedProjectDirectory, "AtmelStart.gpdsc");

            if (!File.Exists(gpdscFile))
            {
                throw new Exception($"{gpdscFile} does not exist!");
            }

            var gccMakefile = Path.Combine(extractedProjectDirectory, "gcc\\Makefile");

            if (!File.Exists(gccMakefile))
            {
                throw new Exception($"{gccMakefile} does not exist. {GCCExportHint}");
            }

            var xml = new XmlDocument();

            xml.Load(gpdscFile);
            string device = null;

            foreach (var node in xml.SelectNodes("package/generators/generator/select").OfType <XmlElement>())
            {
                var name   = node.GetAttribute("Dname");
                var vendor = node.GetAttribute("Dvendor");
                if (!string.IsNullOrEmpty(vendor) && !string.IsNullOrEmpty(name))
                {
                    device = name;
                }
            }

            if (device == null)
            {
                throw new Exception($"Could not find the device ID in {gpdscFile}");
            }

            var flagsFromMakefile = ScanMakefileForCommonFlags(gccMakefile);

            var bsp = new BoardSupportPackage
            {
                PackageID          = "com.sysprogs.arm.samd21",
                GNUTargetID        = "arm-eabi",
                PackageDescription = $"ATSAMD21 Support",
                BSPImporterID      = ID,
                MCUFamilies        = new[] { new MCUFamily {
                                                 ID = "ATSAMD21"
                                             } },
                Frameworks = xml.SelectNodes("package/components/component").OfType <XmlElement>().Select(GenerateFrameworkForComponent).Where(f => f != null).ToArray(),

                EmbeddedSamples = new[]
                {
                    new EmbeddedProjectSample
                    {
                        Name                    = "Default Project",
                        Description             = "A basic project generated by Atmel START",
                        AdditionalSourcesToCopy = new[]
                        {
                            new AdditionalSourceFile
                            {
                                SourcePath     = "$$SYS:BSP_ROOT$$/main.c",
                                TargetFileName = "$$PROJECTNAME$$.c",
                            }
                        }
                    }
                }
            };
            List <MCU> mcus = new List <MCU>();
            Dictionary <string, int> headers = new Dictionary <string, int>();

            string[] strFileMCU    = File.ReadAllLines("../../McuAtmel.csv");
            bool     header_row    = true;
            var      linkerScripts = DetectLinkerScripts(extractedProjectDirectory);

            for (int il = 0; il < strFileMCU.Length; il++)
            {
                string   line  = strFileMCU[il];
                string[] items = line.Split(',');

                if (header_row)
                {
                    for (int i = 0; i < items.Length; i++)
                    {
                        headers[items[i]] = i;
                    }

                    header_row = false;
                    continue;
                }
                String size = items[headers["Device Name"]].Substring(9, 2);
                String LinkerScriptLocation = linkerScripts.RelativeFLASHScript.Substring(0, linkerScripts.RelativeFLASHScript.LastIndexOf("/")) + "/samd21g" + size + "_flash.ld";
                var    memories             = ScanLinkerScriptForMemories(Path.Combine(extractedProjectDirectory, LinkerScriptLocation));
                LinkerScriptLocation = LinkerScriptLocation.Replace("*", "$$com.sysprogs.bspoptions.primary_memory$$");

                LinkerScriptLocation = "$$SYS:BSP_ROOT$$/" + LinkerScriptLocation;
                var newMcu = new MCU
                {
                    ID       = items[headers["Device Name"]],
                    FamilyID = "ATSAMD21",

                    FLASHBase = (uint)0,
                    FLASHSize = Int32.Parse(items[headers["Flash (kBytes)"]]),

                    RAMBase = (uint)536870912,
                    RAMSize = Int32.Parse(items[headers["SRAM (kBytes)"]]),

                    CompilationFlags = new ToolFlags
                    {
                        PreprocessorMacros = new[] { $"__{items[headers["Device Name"]]}__" },
                        COMMONFLAGS        = string.Join(" ", flagsFromMakefile.CommonFlags),
                        LinkerScript       = linkerScripts.LinkerScriptFormat,
                        IncludeDirectories = flagsFromMakefile.RelativeIncludeDirs?.Select(d => "$$SYS:BSP_ROOT$$/" + d).ToArray(),
                        LDFLAGS            = "-Wl,--entry=Reset_Handler",              //Unless this is specified explicitly, the gdb's "load" command won't set $pc to the entry point, requiring an explicit device reset.
                    },

                    ConfigurableProperties = new PropertyList
                    {
                        PropertyGroups = new[] { linkerScripts.ToPropertyGroup() }.Where(g => g != null).ToList()
                    },

                    MemoryMap = new AdvancedMemoryMap
                    {
                        Memories = memories.ToArray()
                    }
                };
                FixGPDSCErrors(bsp, newMcu, extractedProjectDirectory, flagsFromMakefile, linkerScripts.RelativeFLASHScript);
                mcus.Add(newMcu);
            }
            bsp.SupportedMCUs = mcus.ToArray();
            List <AdditionalSourceFile> sourceFilesList = bsp.EmbeddedSamples[0].AdditionalSourcesToCopy.ToList();
            IEnumerable <String>        files           = Directory.EnumerateFiles(extractedProjectDirectory);

            foreach (String item in files)
            {
                String target = "";
                if (item.EndsWith(".h"))
                {
                    target = "inc/" + Path.GetFileName(item);
                }
                else if (item.EndsWith(".c"))
                {
                    target = "src/" + Path.GetFileName(item);
                }
                else
                {
                    continue;
                }
                AdditionalSourceFile a = new AdditionalSourceFile
                {
                    SourcePath     = "$$SYS:BSP_ROOT$$/" + Path.GetFileName(item),
                    TargetFileName = target,
                };
                sourceFilesList.Add(a);
            }
            files = Directory.EnumerateFiles(extractedProjectDirectory + "/config");
            foreach (String item in files)
            {
                String target = "";
                if (item.EndsWith(".h"))
                {
                    target = "config/" + Path.GetFileName(item);
                }
                else
                {
                    continue;
                }
                AdditionalSourceFile a = new AdditionalSourceFile
                {
                    SourcePath     = "$$SYS:BSP_ROOT$$/config/" + Path.GetFileName(item),
                    TargetFileName = target,
                };
                sourceFilesList.Add(a);
            }
            bsp.EmbeddedSamples[0].AdditionalSourcesToCopy = sourceFilesList.ToArray();
            String path = Path.Combine(extractedProjectDirectory, LoadedBSP.PackageFileName);

            XmlTools.SaveObject(bsp, path);
            return(bsp);
        }
Ejemplo n.º 6
0
 public ParserImpl(string sdkDirectory, XmlDocument doc, IWarningSink sink)
 {
     _Directory = sdkDirectory;
     _Manifest  = doc;
     _Sink      = sink;
 }
Ejemplo n.º 7
0
        public string GenerateBSPForSDK(string directory, IWarningSink sink)
        {
            var bsp = ParseKSDKManifest(directory, sink);
            bsp.Save(directory);

            return bsp.BSP.PackageID;
        }
Ejemplo n.º 8
0
        public static ParsedSDK ParseKSDKManifest(string sdkDirectory, IWarningSink sink)
        {
            string[] manifestFiles = Directory.GetFiles(sdkDirectory, "*manifest.xml");
            if (manifestFiles.Length < 1)
                throw new Exception($"No manifest files in {sdkDirectory}");

            string manifestFile = Directory.GetFiles(sdkDirectory, "*manifest.xml")[0];

            List<VendorSample> vsl = new List<VendorSample>();

            XmlDocument doc = new XmlDocument();
            doc.Load(manifestFile);

            List<MCU> mcus = new List<MCU>();
            List<MCUFamily> families = new List<MCUFamily>();
            List<ParsedComponent> allFrameworks = new List<ParsedComponent>();
            bool linkerScriptHandled = false;

            List<string> allFiles = new List<string>();
            Dictionary<string, ParsedDevice> deviceDict = new Dictionary<string, ParsedDevice>();
            Dictionary<string, EmbeddedFramework> frameworkDict = new Dictionary<string, EmbeddedFramework>();
            List<FileCondition> allConditions = new List<FileCondition>();
            string fwPrefix = "com.sysprogs.ksdk2x_imported.";
            HashSet<string> alwaysIncludedFrameworks = new HashSet<string>();

            foreach (XmlElement devNode in doc.SelectNodes("//devices/device"))
            {
                ParsedDevice dev = new ParsedDevice(devNode, sdkDirectory);

                var mcuFamily = dev.ToMCUFamily();

                int FLASHSize, RAMSize;
                int.TryParse((devNode.SelectSingleNode("memory/@flash_size_kb")?.Value ?? ""), out FLASHSize);
                int.TryParse((devNode.SelectSingleNode("memory/@ram_size_kb")?.Value ?? ""), out RAMSize);
                FLASHSize *= 1024;
                RAMSize *= 1024;

                families.Add(mcuFamily);
                string svdFile = null;

                //Map each component to an instance of EmbeddedFramework
                foreach (XmlNode componentNode in doc.SelectNodes($"//components/component"))
                {
                    string componentName = componentNode.SelectSingleNode("@name")?.Value ?? "";
                    string componentType = componentNode.SelectSingleNode("@type")?.Value ?? "";
                    string device = componentNode.SelectSingleNode("@device")?.Value ?? "";

                    switch (componentType)
                    {
                        case "documentation":
                        case "SCR":
                        case "EULA":
                            continue;
                        case "debugger":
                        case "linker":
                            {
                                List<string> relPaths = new List<string>();
                                bool isDebug = componentType == "debugger";
                                string sourceType = isDebug ? "debug" : "linker";
                                foreach (var src in componentNode.SelectNodes($"source[@type='{sourceType}']").OfType<XmlElement>().Select(e => new ParsedSource(e, dev)))
                                {
                                    foreach (var fn in src.AllFiles)
                                    {
                                        relPaths.Add(fn.RelativePath);
                                    }
                                }

                                if (relPaths.Count > 0)
                                {
                                    if (isDebug)
                                        svdFile = relPaths[0];
                                    else if (!linkerScriptHandled)
                                    {
                                        linkerScriptHandled = true;
                                        if (relPaths.Count == 1)
                                            mcuFamily.CompilationFlags.LinkerScript = "$$SYS:BSP_ROOT$$/" + relPaths[0];
                                        else
                                        {
                                            const string optionID = "com.sysprogs.imported.ksdk2x.linker_script";
                                            mcuFamily.CompilationFlags.LinkerScript = $"$$SYS:BSP_ROOT$$/$${optionID}$$";
                                            mcuFamily.ConfigurableProperties.PropertyGroups[0].Properties.Add(new PropertyEntry.Enumerated
                                            {
                                                UniqueID = optionID,
                                                Name = "Linker script",
                                                AllowFreeEntry = false,
                                                SuggestionList = relPaths.Select(p => new PropertyEntry.Enumerated.Suggestion { InternalValue = p, UserFriendlyName = Path.GetFileName(p) }).ToArray()
                                            });
                                        }
                                    }
                                }
                            }
                            continue;
                        case "CMSIS":
                            //KSDK 2.x defines a Include_xxx framework for each possible CMSIS core. Those frameworks are redundant (normal 'Include' framework references the same include path) and should be removed to avoid confusion.
                            if (componentName.StartsWith("Include_"))
                                continue;
                            if (componentName == "Include")
                                alwaysIncludedFrameworks.Add(fwPrefix + componentName);
                            break;
                        default:
                            break;
                    }

                    List<string> headerFiles = new List<string>();
                    List<string> includeDirectories = new List<string>();
                    List<string> sourceFiles = new List<string>();

                    foreach (ParsedSource src in componentNode.SelectNodes("source").OfType<XmlElement>().Select(e => new ParsedSource(e, dev)))
                    {
                        if (src.Type == "c_include")
                            includeDirectories.Add(src.BSPPath);

                        foreach (var file in src.AllFiles)
                        {
                            if (src.Type == "src" || src.Type == "asm_include")
                                sourceFiles.Add(file.BSPPath);
                            else if (src.Type == "c_include")
                                headerFiles.Add(file.BSPPath);
                        }
                    }

                    if (componentName == "clock" && componentType == "driver")
                        alwaysIncludedFrameworks.Add(fwPrefix + componentName);

                    string[] dependencyList = componentNode.Attributes?.GetNamedItem("dependency")?.Value?.Split(' ')
                        ?.Select(id => fwPrefix + id)
                        ?.ToArray() ?? new string[0];

                    EmbeddedFramework fw = new EmbeddedFramework
                    {
                        ID = $"{fwPrefix}{componentName}",
                        UserFriendlyName = $"{componentName} ({componentType})",
                        ProjectFolderName = componentName,
                        AdditionalSourceFiles = sourceFiles.Distinct().ToArray(),
                        AdditionalHeaderFiles = headerFiles.Distinct().ToArray(),
                        RequiredFrameworks = dependencyList,
                        AdditionalIncludeDirs = includeDirectories.Distinct().ToArray(),
                        AdditionalPreprocessorMacros = componentNode.SelectNodes("defines/define").OfType<XmlElement>().Select(el => new ParsedDefine(el).Definition).ToArray(),
                    };

                    if (componentName == "freertos" && componentType == "OS")
                    {
                        fw.AdditionalPreprocessorMacros = LoadedBSP.Combine(fw.AdditionalPreprocessorMacros, "USE_RTOS=1;USE_FREERTOS".Split(';'));
                        fw.ConfigurableProperties = new PropertyList
                        {
                            PropertyGroups = new List<PropertyGroup>()
                            {
                                new PropertyGroup
                                {
                                    Properties = new List<PropertyEntry>()
                                    {
                                        new PropertyEntry.Enumerated
                                        {
                                            Name = "FreeRTOS Heap Implementation",
                                            UniqueID = "com.sysprogs.bspoptions.stm32.freertos.heap",
                                            DefaultEntryIndex = 3,
                                            SuggestionList = new PropertyEntry.Enumerated.Suggestion[]
                                            {
                                                new PropertyEntry.Enumerated.Suggestion{InternalValue = "heap_1", UserFriendlyName = "Heap1 - no support for freeing"},
                                                new PropertyEntry.Enumerated.Suggestion{InternalValue = "heap_2", UserFriendlyName = "Heap2 - no block consolidation"},
                                                new PropertyEntry.Enumerated.Suggestion{InternalValue = "heap_3", UserFriendlyName = "Heap3 - use newlib malloc()/free()"},
                                                new PropertyEntry.Enumerated.Suggestion{InternalValue = "heap_4", UserFriendlyName = "Heap4 - contiguous heap area"},
                                                new PropertyEntry.Enumerated.Suggestion{InternalValue = "heap_5", UserFriendlyName = "Heap5 - scattered heap area"},
                                            }
                                        }
                                    }
                                }
                            }
                        };

                        foreach(var fn in fw.AdditionalSourceFiles)
                        {
                            string name = Path.GetFileName(fn);
                            if (name.StartsWith("heap_"))
                            {
                                allConditions.Add(new FileCondition { FilePath = fn, ConditionToInclude = new Condition.Equals { Expression = "$$com.sysprogs.bspoptions.stm32.freertos.heap$$", ExpectedValue = Path.GetFileNameWithoutExtension(fn) } });
                            }
                        }
                    }

                    if (frameworkDict.ContainsKey(fw.ID))
                    {
                        sink.LogWarning("Duplicate framework for " + fw.ID);
                        continue;
                    }

                    frameworkDict[fw.ID] = fw;

                    if (string.IsNullOrEmpty(fw.ID))
                    {
                        sink.LogWarning($"Found a framework with empty ID. Skipping...");
                        continue;
                    }

                    if (string.IsNullOrEmpty(fw.UserFriendlyName))
                        fw.UserFriendlyName = fw.ID;

                    allFrameworks.Add(new ParsedComponent { Framework = fw, OriginalType = componentType, OriginalName = componentName });
                    allFiles.AddRange(sourceFiles);
                    allFiles.AddRange(headerFiles);
                }

                string deviceDefinitionFile = null;
                if (svdFile != null)
                {
                    try
                    {
                        var mcuDef = SVDParser.ParseSVDFile(Path.Combine(sdkDirectory, svdFile), dev.DeviceName);
                        deviceDefinitionFile = Path.ChangeExtension(svdFile, ".vgdbdevice");

                        XmlSerializer ser = new XmlSerializer(typeof(MCUDefinition));
                        using (var fs = File.Create(Path.Combine(sdkDirectory, Path.ChangeExtension(svdFile, ".vgdbdevice.gz"))))
                        using (var gs = new GZipStream(fs, CompressionMode.Compress, true))
                            ser.Serialize(gs, new MCUDefinition(mcuDef));
                    }
                    catch (Exception ex)
                    {
                        sink.LogWarning($"Failed to parse {svdFile}: {ex.Message}");
                    }
                }

                foreach (XmlNode packageNode in devNode.SelectNodes($"package/@name"))
                {
                    string pkgName = packageNode?.Value;
                    if (string.IsNullOrEmpty(pkgName))
                        continue;

                    deviceDict[pkgName] = dev;

                    mcus.Add(new MCU
                    {
                        ID = pkgName,
                        UserFriendlyName = $"{pkgName} (KSDK 2.x)",
                        FamilyID = mcuFamily.ID,
                        FLASHSize = FLASHSize,
                        RAMSize = RAMSize,
                        CompilationFlags = new ToolFlags
                        {
                            PreprocessorMacros = new string[] { "CPU_" + pkgName }
                        },

                        MCUDefinitionFile = deviceDefinitionFile
                    });
                }
            }

            if (families.Count == 0)
                throw new Exception("The selected KSDK contains no families");

            List<VendorSample> samples = new List<VendorSample>();

            foreach (XmlElement boardNode in doc.SelectNodes("//boards/board"))
            {
                string boardName = boardNode.GetAttribute("name");
                string deviceID = boardNode.GetAttribute("package");
                ParsedDevice dev;
                if (!deviceDict.TryGetValue(deviceID, out dev))
                    continue;

                foreach (XmlElement exampleNode in boardNode.SelectNodes("examples/example"))
                {
                    List<string> dependencyList = new List<string>(exampleNode.Attributes?.GetNamedItem("dependency")?.Value?.Split(' ')
                        ?.Select(id => fwPrefix + id) ?? new string[0]);

                    dependencyList.AddRange(alwaysIncludedFrameworks);

                    for (int i = 0; i < dependencyList.Count; i++)
                    {
                        EmbeddedFramework fw;
                        if (frameworkDict.TryGetValue(dependencyList[i], out fw) && fw?.RequiredFrameworks != null)
                            dependencyList.AddRange(fw.RequiredFrameworks.Except(dependencyList));
                    }

                    VendorSample sample = new VendorSample
                    {
                        DeviceID = deviceID,
                        UserFriendlyName = exampleNode.GetAttribute("name") ?? "???",
                        BoardName = boardName,
                        Configuration = new VendorSampleConfiguration
                        {
                            Frameworks = dependencyList.ToArray()
                        },
                        VirtualPath = exampleNode.GetAttribute("category"),
                        NoImplicitCopy = true
                    };

                    List<string> headerFiles = new List<string>();
                    List<string> includeDirectories = new List<string>();
                    List<string> sourceFiles = new List<string>();

                    foreach (var src in exampleNode.SelectNodes("source").OfType<XmlElement>().Select(e => new ParsedSource(e, dev)))
                    {
                        foreach (var file in src.AllFiles)
                        {
                            if (src.Type == "src" || src.Type == "asm_include")
                                sourceFiles.Add(file.BSPPath);
                            else if (src.Type == "c_include")
                                headerFiles.Add(file.BSPPath);
                        }
                    }

                    sample.SourceFiles = sourceFiles.ToArray();
                    sample.HeaderFiles = headerFiles.ToArray();

                    if (sourceFiles.Count == 0 && headerFiles.Count == 0)
                        continue;

                    string[] matchingComponents = null;

                    foreach (var fn in sourceFiles.Concat(headerFiles))
                    {
                        string[] components = fn.Split('/', '\\');
                        if (matchingComponents == null)
                            matchingComponents = components;
                        else
                        {
                            int matches = CountMatches(matchingComponents, components);
                            if (matches < matchingComponents.Length)
                                Array.Resize(ref matchingComponents, matches);
                        }
                    }

                    if (matchingComponents != null)
                        sample.Path = string.Join("/", matchingComponents);

                    samples.Add(sample);
                }
            }

            return new ParsedSDK
            {
                BSP = new BoardSupportPackage
                {
                    PackageID = "com.sysprogs.imported.ksdk2x." + families[0].ID,
                    PackageDescription = "Imported KSDK 2.x for " + families[0].ID,
                    PackageVersion = doc.SelectSingleNode("//ksdk/@version")?.Value ?? "unknown",
                    GNUTargetID = "arm-eabi",
                    Frameworks = allFrameworks.Where(f => f.OriginalType != "project_template").Select(f => f.Framework).ToArray(),
                    MCUFamilies = families.ToArray(),
                    SupportedMCUs = mcus.ToArray(),
                    FileConditions = allFiles
                        .Where(f => f.IndexOf("freertos", StringComparison.InvariantCultureIgnoreCase) != -1)
                        .Select(f => new FileCondition { FilePath = f, ConditionToInclude = new Condition.ReferencesFramework { FrameworkID = fwPrefix + "freertos" } })
                        .Concat(allConditions)
                        .ToArray(),
                    VendorSampleCatalogName = "KSDK Samples",
                    EmbeddedSamples = allFrameworks.Where(f => f.OriginalType == "project_template").Select(f => f.ToProjectSample(alwaysIncludedFrameworks)).ToArray(),
                },

                VendorSampleDirectory = new VendorSampleDirectory
                {
                    Samples = samples.ToArray()
                }
            };
        }