예제 #1
0
파일: Program.cs 프로젝트: xllj/BSPTools
        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                throw new Exception("Usage: stm32.exe <SW package directory> <STM32Cube directory>");
            }

            ///If the MCU list format changes again, create a new implementation of the IDeviceListProvider interface, switch to using it, but keep the old one for reference & easy comparison.
            IDeviceListProvider provider = new DeviceListProviders.CubeProvider();

            var bspBuilder = new STM32BSPBuilder(new BSPDirectories(args[0], @"..\..\Output", @"..\..\rules"), args[1]);

            var devices = provider.LoadDeviceList(bspBuilder);

            if (devices.Where(d => d.RAMSize == 0 || d.FlashSize == 0).Count() > 0)
            {
                throw new Exception($"Some devices are RAM Size ({devices.Where(d => d.RAMSize == 0).Count()})  = 0 or FLASH Size({devices.Where(d => d.FlashSize == 0).Count()})  = 0 ");
            }


            List <MCUFamilyBuilder> allFamilies = new List <MCUFamilyBuilder>();

            foreach (var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml"))
            {
                allFamilies.Add(new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(fn)));
            }

            var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies);

            if (rejects.Count > 0)
            {
                Console.WriteLine("Globally unsupported MCUs:");
                foreach (var r in rejects)
                {
                    Console.WriteLine("\t{0}", r.Name);
                }
            }

            List <MCUFamily>                     familyDefinitions = new List <MCUFamily>();
            List <MCU>                           mcuDefinitions    = new List <MCU>();
            List <EmbeddedFramework>             frameworks        = new List <EmbeddedFramework>();
            List <MCUFamilyBuilder.CopiedSample> exampleDirs       = new List <MCUFamilyBuilder.CopiedSample>();

            bool noPeripheralRegisters = args.Contains("/noperiph");

            var files = string.Join("\r\n", File.ReadAllLines(@"E:\ware\Logfile.CSV").Select(l => l.Split(',')[4].Trim('\"')).Distinct().OrderBy(x => x).ToArray());

            var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml"));

            foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions())
            {
                frameworks.Add(fw);
            }

            foreach (var fam in allFamilies)
            {
                bspBuilder.GetMemoryMcu(fam);
                var rejectedMCUs = fam.RemoveUnsupportedMCUs(true);
                if (rejectedMCUs.Length != 0)
                {
                    Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name);
                    foreach (var mcu in rejectedMCUs)
                    {
                        Console.WriteLine("\t{0}", mcu.Name);
                    }
                }

                fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam));
                if (!noPeripheralRegisters)
                {
                    fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam));
                }

                familyDefinitions.Add(fam.GenerateFamilyObject(true));
                fam.GenerateLinkerScripts(false);
                foreach (var mcu in fam.MCUs)
                {
                    mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters));
                }

                foreach (var fw in fam.GenerateFrameworkDefinitions())
                {
                    frameworks.Add(fw);
                }

                foreach (var sample in fam.CopySamples())
                {
                    exampleDirs.Add(sample);
                }
            }

            foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars)))
            {
                exampleDirs.Add(sample);
            }

            var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt"));

            exampleDirs.Sort((a, b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath));

            BoardSupportPackage bsp = new BoardSupportPackage
            {
                PackageID                         = "com.sysprogs.arm.stm32",
                PackageDescription                = "STM32 Devices",
                GNUTargetID                       = "arm-eabi",
                GeneratedMakFileName              = "stm32.mak",
                MCUFamilies                       = familyDefinitions.ToArray(),
                SupportedMCUs                     = mcuDefinitions.ToArray(),
                Frameworks                        = frameworks.ToArray(),
                Examples                          = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(),
                TestExamples                      = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(),
                PackageVersion                    = "4.5R2",
                IntelliSenseSetupFile             = "stm32_compat.h",
                FileConditions                    = bspBuilder.MatchedFileConditions.ToArray(),
                MinimumEngineVersion              = "5.1",
                FirstCompatibleVersion            = "3.0",
                InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints,
            };

            File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true);
            Console.WriteLine("Saving BSP...");
            bspBuilder.Save(bsp, true);
        }
예제 #2
0
        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                throw new Exception("Usage: stm32.exe <SW package directory> <STM32Cube directory>");
            }

            var bspBuilder = new STM32BSPBuilder(new BSPDirectories(args[0], @"..\..\Output", @"..\..\rules"), args[1]);
            var devices    = BSPGeneratorTools.ReadMCUDevicesFromCommaDelimitedCSVFile(bspBuilder.Directories.RulesDir + @"\stm32devices.csv", "Part Number", "FLASH Size (Prog)", "Internal RAM Size", "Core", true);
            List <MCUFamilyBuilder> allFamilies = new List <MCUFamilyBuilder>();

            foreach (var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml"))
            {
                allFamilies.Add(new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(fn)));
            }

            var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies);

            if (rejects.Count > 0)
            {
                Console.WriteLine("Globally unsupported MCUs:");
                foreach (var r in rejects)
                {
                    Console.WriteLine("\t{0}", r.Name);
                }
            }

            List <MCUFamily>                     familyDefinitions = new List <MCUFamily>();
            List <MCU>                           mcuDefinitions    = new List <MCU>();
            List <EmbeddedFramework>             frameworks        = new List <EmbeddedFramework>();
            List <MCUFamilyBuilder.CopiedSample> exampleDirs       = new List <MCUFamilyBuilder.CopiedSample>();

            bool noPeripheralRegisters = args.Contains("/noperiph");

            var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml"));

            foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions())
            {
                frameworks.Add(fw);
            }

            foreach (var fam in allFamilies)
            {
                bspBuilder.GetMemoryMcu(fam);
                var rejectedMCUs = fam.RemoveUnsupportedMCUs(true);
                if (rejectedMCUs.Length != 0)
                {
                    Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name);
                    foreach (var mcu in rejectedMCUs)
                    {
                        Console.WriteLine("\t{0}", mcu.Name);
                    }
                }

                fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam));
                if (!noPeripheralRegisters)
                {
                    fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam));
                }

                familyDefinitions.Add(fam.GenerateFamilyObject(true));
                fam.GenerateLinkerScripts(false);
                foreach (var mcu in fam.MCUs)
                {
                    mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters));
                }

                foreach (var fw in fam.GenerateFrameworkDefinitions())
                {
                    frameworks.Add(fw);
                }

                foreach (var sample in fam.CopySamples())
                {
                    exampleDirs.Add(sample);
                }
            }

            foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars)))
            {
                exampleDirs.Add(sample);
            }

            var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt"));

            exampleDirs.Sort((a, b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath));

            BoardSupportPackage bsp = new BoardSupportPackage
            {
                PackageID                         = "com.sysprogs.arm.stm32",
                PackageDescription                = "STM32 Devices",
                GNUTargetID                       = "arm-eabi",
                GeneratedMakFileName              = "stm32.mak",
                MCUFamilies                       = familyDefinitions.ToArray(),
                SupportedMCUs                     = mcuDefinitions.ToArray(),
                Frameworks                        = frameworks.ToArray(),
                Examples                          = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(),
                TestExamples                      = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(),
                PackageVersion                    = "4.1",
                IntelliSenseSetupFile             = "stm32_compat.h",
                FileConditions                    = bspBuilder.MatchedFileConditions.ToArray(),
                MinimumEngineVersion              = "5.1",
                FirstCompatibleVersion            = "3.0",
                InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints,
            };

            File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true);
            Console.WriteLine("Saving BSP...");
            bspBuilder.Save(bsp, true);
        }
예제 #3
0
        static void Main(string[] args)
        {
            var regKey   = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Sysprogs\BSPGenerators\STM32");
            var sdkRoot  = regKey.GetValue("SDKRoot") as string ?? throw new Exception("Please specify STM32 SDK root via registry");
            var cubeRoot = regKey.GetValue("CubeMXRoot") as string ?? throw new Exception("Please specify STM32CubeMX location via registry");

            if (args.Contains("/fetch"))
            {
                //This will load the latest SDK list from the STM32CubeMX directory and will fetch/unpack them to our SDKRoot directory.
                //Before running this, ensure the STM32CubeMX has the up-to-date SDK definitions (using the 'check for update' function), as
                //otherwise the BSP generator will fetch the old versions.

                SDKFetcher.FetchLatestSDKs(sdkRoot, cubeRoot);
            }

            string       rulesetName = args.FirstOrDefault(a => a.StartsWith("/rules:"))?.Substring(7) ?? STM32Ruleset.Classic.ToString();
            STM32Ruleset ruleset     = Enum.GetValues(typeof(STM32Ruleset))
                                       .OfType <STM32Ruleset>()
                                       .First(v => StringComparer.InvariantCultureIgnoreCase.Compare(v.ToString(), rulesetName) == 0);

            ///If the MCU list format changes again, create a new implementation of the IDeviceListProvider interface, switch to using it, but keep the old one for reference & easy comparison.
            IDeviceListProvider provider = new DeviceListProviders.CubeProvider();

            var bspBuilder = new STM32BSPBuilder(new BSPDirectories(sdkRoot, @"..\..\Output\" + rulesetName, @"..\..\rules\" + rulesetName), cubeRoot);

            Directory.CreateDirectory(@"..\..\Logs");
            using (var wr = new ParseReportWriter(@"..\..\Logs\registers.log"))
            {
                var devices = provider.LoadDeviceList(bspBuilder);
                if (devices.Where(d => d.FlashSize == 0 && !d.Name.StartsWith("STM32MP1")).Count() > 0)
                {
                    throw new Exception($"Some deviceshave FLASH Size({devices.Where(d => d.FlashSize == 0).Count()})  = 0 ");
                }

                List <MCUFamilyBuilder> allFamilies = new List <MCUFamilyBuilder>();
                string extraFrameworksFile          = Path.Combine(bspBuilder.Directories.RulesDir, "FrameworkTemplates.xml");
                if (!File.Exists(extraFrameworksFile) && File.Exists(Path.ChangeExtension(extraFrameworksFile, ".txt")))
                {
                    extraFrameworksFile = Path.Combine(bspBuilder.Directories.RulesDir, File.ReadAllText(Path.ChangeExtension(extraFrameworksFile, ".txt")));
                }

                Dictionary <string, STM32SDKCollection.SDK> sdksByVariable = bspBuilder.SDKList.SDKs.ToDictionary(s => $"$$STM32:{s.Family}_DIR$$");
                List <STM32SDKCollection.SDK> referencedSDKs = new List <STM32SDKCollection.SDK>();

                foreach (var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml"))
                {
                    var fam = XmlTools.LoadObject <FamilyDefinition>(fn);

                    if (File.Exists(extraFrameworksFile))
                    {
                        int    idx     = fam.PrimaryHeaderDir.IndexOf('\\');
                        string baseDir = fam.PrimaryHeaderDir.Substring(0, idx);
                        if (!baseDir.StartsWith("$$STM32:"))
                        {
                            throw new Exception("Invalid base directory. Please recheck the family definition.");
                        }

                        string baseFamName = fam.Name;
                        if (baseFamName.EndsWith("_M4"))
                        {
                            baseFamName = baseFamName.Substring(0, baseFamName.Length - 3);
                        }

                        referencedSDKs.Add(sdksByVariable[baseDir]);

                        var dict = new Dictionary <string, string>
                        {
                            { "STM32:FAMILY_EX", fam.Name },
                            { "STM32:FAMILY", baseFamName },
                            { "STM32:FAMILY_DIR", baseDir },
                        };

                        var extraFrameworkFamily = XmlTools.LoadObject <FamilyDefinition>(extraFrameworksFile);

                        //USB host/device libraries are not always compatible between different device families. Hence we need to ship separate per-family copies of those.
                        var expandedExtraFrameworks = extraFrameworkFamily.AdditionalFrameworks.Select(fw =>
                        {
                            fw.ID   = VariableHelper.ExpandVariables(fw.ID, dict);
                            fw.Name = VariableHelper.ExpandVariables(fw.Name, dict);
                            fw.RequiredFrameworks     = ExpandVariables(fw.RequiredFrameworks, dict);
                            fw.IncompatibleFrameworks = ExpandVariables(fw.IncompatibleFrameworks, dict);
                            foreach (var job in fw.CopyJobs)
                            {
                                job.SourceFolder          = VariableHelper.ExpandVariables(job.SourceFolder, dict);
                                job.TargetFolder          = VariableHelper.ExpandVariables(job.TargetFolder, dict);
                                job.AdditionalIncludeDirs = VariableHelper.ExpandVariables(job.AdditionalIncludeDirs, dict);
                            }

                            return(fw);
                        });

                        //Furthermore, some families do not include a USB host peripheral and hence do not contain a USB Host library. We need to skip it automatically.
                        var extraFrameworksWithoutMissingFolders = expandedExtraFrameworks.Where(fw => fw.CopyJobs.Count(j =>
                        {
                            string expandedJobSourceDir = j.SourceFolder;
                            bspBuilder.ExpandVariables(ref expandedJobSourceDir);
                            return(!Directory.Exists(expandedJobSourceDir));
                        }) == 0);

                        fam.AdditionalFrameworks = fam.AdditionalFrameworks.Concat(extraFrameworksWithoutMissingFolders).ToArray();
                    }

                    bspBuilder.InsertLegacyHALRulesIfNecessary(fam, bspBuilder.ReverseFileConditions);
                    switch (ruleset)
                    {
                    case STM32Ruleset.STM32WB:
                        allFamilies.Add(new STM32WBFamilyBuilder(bspBuilder, fam));
                        break;

                    case STM32Ruleset.STM32MP1:
                        allFamilies.Add(new STM32MP1FamilyBuilder(bspBuilder, fam));
                        break;

                    case STM32Ruleset.Classic:
                    default:
                        allFamilies.Add(new STM32ClassicFamilyBuilder(bspBuilder, fam));
                        break;
                    }
                }

                var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies);

                if (rejects.Count > 0 && ruleset == STM32Ruleset.Classic)
                {
                    Console.WriteLine("Globally unsupported MCUs:");
                    foreach (var r in rejects)
                    {
                        Console.WriteLine("\t{0}", r.Name);
                    }
                }

                List <MCUFamily>                     familyDefinitions = new List <MCUFamily>();
                List <MCU>                           mcuDefinitions    = new List <MCU>();
                List <EmbeddedFramework>             frameworks        = new List <EmbeddedFramework>();
                List <MCUFamilyBuilder.CopiedSample> exampleDirs       = new List <MCUFamilyBuilder.CopiedSample>();

                bool   noPeripheralRegisters = args.Contains("/noperiph");
                string specificDeviceForDebuggingPeripheralRegisterGenerator = args.FirstOrDefault(a => a.StartsWith("/periph:"))?.Substring(8);

                var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml"));
                foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions())
                {
                    frameworks.Add(fw);
                }

                List <ConditionalToolFlags> allConditionalToolFlags = new List <ConditionalToolFlags>();

                foreach (var fam in allFamilies)
                {
                    bspBuilder.GetMemoryMcu(fam);
                    var rejectedMCUs = fam.RemoveUnsupportedMCUs(true);
                    if (rejectedMCUs.Length != 0)
                    {
                        Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name);
                        foreach (var mcu in rejectedMCUs)
                        {
                            Console.WriteLine("\t{0}", mcu.Name);
                        }
                    }

                    fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam));
                    if (!noPeripheralRegisters)
                    {
                        fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam, specificDeviceForDebuggingPeripheralRegisterGenerator, wr),
                                                      throwIfNotFound: specificDeviceForDebuggingPeripheralRegisterGenerator == null);
                    }

                    familyDefinitions.Add(fam.GenerateFamilyObject(MCUFamilyBuilder.CoreSpecificFlags.All, true));
                    fam.GenerateLinkerScripts(false);

                    foreach (var mcu in fam.MCUs)
                    {
                        mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters && specificDeviceForDebuggingPeripheralRegisterGenerator == null));
                    }

                    foreach (var fw in fam.GenerateFrameworkDefinitions())
                    {
                        frameworks.Add(fw);
                    }

                    foreach (var sample in fam.CopySamples())
                    {
                        exampleDirs.Add(sample);
                    }

                    if (fam.Definition.ConditionalFlags != null)
                    {
                        allConditionalToolFlags.AddRange(fam.Definition.ConditionalFlags);
                    }
                }

                foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars)))
                {
                    exampleDirs.Add(sample);
                }

                var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt"));
                exampleDirs.Sort((a, b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath));

                var bsp = XmlTools.LoadObject <BoardSupportPackage>(Path.Combine(bspBuilder.Directories.RulesDir, "BSPTemplate.xml"));

                bsp.MCUFamilies    = familyDefinitions.ToArray();
                bsp.SupportedMCUs  = mcuDefinitions.ToArray();
                bsp.Frameworks     = frameworks.ToArray();
                bsp.Examples       = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray();
                bsp.TestExamples   = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray();
                bsp.PackageVersion = bspBuilder.SDKList.BSPVersion;
                bsp.FileConditions = bspBuilder.MatchedFileConditions.ToArray();
                bsp.InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints;
                bsp.ConditionalFlags = allConditionalToolFlags.ToArray();

                bspBuilder.SDKList.SDKs = referencedSDKs.Distinct().ToArray();
                XmlTools.SaveObject(bspBuilder.SDKList, Path.Combine(bspBuilder.BSPRoot, "SDKVersions.xml"));

                bspBuilder.ValidateBSP(bsp);

                bspBuilder.ReverseFileConditions.SaveIfConsistent(bspBuilder.Directories.OutputDir, bspBuilder.ExportRenamedFileTable(), ruleset == STM32Ruleset.STM32WB);

                File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true);
                Console.WriteLine("Saving BSP...");
                bspBuilder.Save(bsp, true);
            }
        }
예제 #4
0
        static void Main(string[] args)
        {
            if (args.Length < 2)
                throw new Exception("Usage: stm32.exe <SW package directory> <STM32Cube directory>");

            var bspBuilder = new STM32BSPBuilder(new BSPDirectories(args[0], @"..\..\Output", @"..\..\rules"), args[1]);
            var devices = BSPGeneratorTools.ReadMCUDevicesFromCommaDelimitedCSVFile(bspBuilder.Directories.RulesDir + @"\stm32devices.csv", "Part Number", "FLASH Size (Prog)", "Internal RAM Size", "Core", true);
            List<MCUFamilyBuilder> allFamilies = new List<MCUFamilyBuilder>();
            foreach(var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml"))
                allFamilies.Add(new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject<FamilyDefinition>(fn)));

            var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies);

            if (rejects.Count > 0)
            {
                Console.WriteLine("Globally unsupported MCUs:");
                foreach (var r in rejects)
                    Console.WriteLine("\t{0}", r.Name);
            }

            List<MCUFamily> familyDefinitions = new List<MCUFamily>();
            List<MCU> mcuDefinitions = new List<MCU>();
            List<EmbeddedFramework> frameworks = new List<EmbeddedFramework>();
            List<MCUFamilyBuilder.CopiedSample> exampleDirs = new List<MCUFamilyBuilder.CopiedSample>();

            bool noPeripheralRegisters = args.Contains("/noperiph");

            var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject<FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml"));
            foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions())
                frameworks.Add(fw);

            foreach (var fam in allFamilies)
            {
                bspBuilder.GetMemoryMcu(fam);
                var rejectedMCUs = fam.RemoveUnsupportedMCUs(true);
                if (rejectedMCUs.Length != 0)
                {
                    Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name);
                    foreach (var mcu in rejectedMCUs)
                        Console.WriteLine("\t{0}", mcu.Name);
                }

                fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam));
                if (!noPeripheralRegisters)
                    fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam));

                familyDefinitions.Add(fam.GenerateFamilyObject(true));
                fam.GenerateLinkerScripts(false);
                foreach (var mcu in fam.MCUs)
                    mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters));

                foreach (var fw in fam.GenerateFrameworkDefinitions())
                    frameworks.Add(fw);

                foreach (var sample in fam.CopySamples())
                    exampleDirs.Add(sample);
            }

            foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars)))
                exampleDirs.Add(sample);

            var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt"));
            exampleDirs.Sort((a,b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath));

            BoardSupportPackage bsp = new BoardSupportPackage
            {
                PackageID = "com.sysprogs.arm.stm32",
                PackageDescription = "STM32 Devices",
                GNUTargetID = "arm-eabi",
                GeneratedMakFileName = "stm32.mak",
                MCUFamilies = familyDefinitions.ToArray(),
                SupportedMCUs = mcuDefinitions.ToArray(),
                Frameworks = frameworks.ToArray(),
                Examples = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(),
                TestExamples = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(),
                PackageVersion = "4.0",
                IntelliSenseSetupFile = "stm32_compat.h",
                FileConditions = bspBuilder.MatchedFileConditions.ToArray(),
                MinimumEngineVersion = "5.1",
                FirstCompatibleVersion = "3.0",
                InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints,
            };

            File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true);
            Console.WriteLine("Saving BSP...");
            bspBuilder.Save(bsp, true);
        }