Continuous Integration: An Implementation Using Altium Designer

July 8, 2019 Ari Mahpour

In a previous article, Continuous Integration and Deployment in ECAD, we discussed the concept of Continuous Integration while testing within a build system (leveraging Git). In this article, we will take a deeper look at how to set this up and run these “tests” against one’s PCB design project.

Continuous Integration Tests: Revisited

In Software Engineering, the purpose of implementing Continuous Integration into a workflow is to prevent one’s code commits from breaking the code in the master system (also known as the “master branch”). When we run tests against our design on every code commit we ensure that the designer has not “broken” anything throughout the design life cycle. This concept of testing at every commit can be extended into the ECAD world. External factors, such as parts availability, can “break” our design without us even knowing it (hence the creation of tools such as Altium Designer’s ActiveBOM Manager). The purpose of introducing unit tests within the Continuous Integration process is to catch those failures early on in the background.

Each person’s criteria for what constitutes a “broken” design will be different, but the fundamental concept is the same. Some designers will not allow a design to move to production until all warnings and errors are cleared within the Electrical Rule Check report. Others may not allow components that are deemed “Not Recommended for New Design.” Mostly everyone, however, will agree that a component must be in stock for them to purchase their full bill of materials (BOM).

Some example criteria that one may choose to test against can be:

  1. Component Availability: Is the part in stock?

  2. Revision State: Is the component released in the right state (Prototype vs. Production)?

  3. Component Lifecycle: Is the component recommended for new designs?

Luckily Altium Designer’s ActiveBOM Manager does all the heavy lifting for you so you don’t need to write custom APIs to part suppliers. The key is integrating this feature into your Continuous Integration system. By doing so it enables this check to happen every time you’ve committed your changes to the server and prevents the designer from—yet another— manual step.

Example: Component Validation

This example checks the following criteria within the build system:

  1. Component Availability: Is the part in stock?

  2. Revision State: Is the component released in the right state?

  3. Component Lifecycle: Is the component recommended for new designs?

  4. Temperature Range: Do the components meet the temperature range criteria specified by the component engineer?

The criteria in this example are identical to the one specified above, except an additional check, temperature range, was added. As mentioned earlier, each designer or company will have different criteria for “passing” their design tests, therefore, this example will not serve as a one-size-fits-all solution. Here you can see that our build system, Bamboo, is reporting a series of failures when performing unit tests against our Altium Designer project:

Figure 1. Bamboo Unit Test results

The following image is a screenshot of an HTML page generated from the BOM and build test results based on criterias 1-4:

Figure 2. Test results from Bamboo illustrated in a reformatted BOM HTML table

This component validation table gets generated each time a commit is pushed to the server. Each member of the team is able to observe any failures that occur on every single Git commit (which happens almost daily for us). Additionally, these “builds” can be triggered from virtually anything or run on a schedule (e.g. nightly). This pairs nicely with your corporate MRP system which can trigger a component stock check test every time a new order comes in.

Implementation

Step 1: Configure your Output Job using the output files needed for your build system. In the example above, a CSV file was generated so it could be easily parsed by our build engine.

Figure 3. Output Job configuration for supplying files to Build system

Figure 4. Output Job column headers to test against

Step 2: Set up the following Delphi script to programmatically generate your Output Jobs:

Procedure GenerateOutputFiles;
Var
    ProjectFilePath   : String;
    WS            : IWorkspace;
    Prj           : IProject;
    Document      : IServerDocument;
Begin
    // Set the Project file path
    ProjectFilePath := '<Path_to_Project>';
    
    // Reset all parameters
    ResetParameters;
    
    // Open the project
    AddStringParameter('ObjectKind','Project');
    AddStringParameter('FileName', ProjectFilePath);
    RunProcess('WorkspaceManager:OpenObject');
    ResetParameters;
    
	// Requirement: OutJob file name is Build.OutJob and is exists within the project
    Document := Client.OpenDocument('OUTPUTJOB', ExtractFilePath(ProjectFilePath) + 'Build.OutJob');
    If Document <> Nil Then
    Begin
        WS := GetWorkspace;
        If WS <> Nil Then
        Begin
            Prj := WS.DM_FocusedProject;
            If Prj <> Nil Then
            Begin            
                // Compile the project
                Prj.DM_Compile;
                Client.ShowDocument(Document);
                
                // Run Output Job
                AddStringParameter('ObjectKind', 'OutputBatch');
                AddStringParameter('Action', 'Run');
                RunProcess('WorkSpaceManager:GenerateReport');
            End;
        End;
    End;
    
    // Close all objects
    AddStringParameter('ObjectKind','All');
    RunProcess('WorkspaceManager:CloseObject');
    ResetParameters;
    
    // Close Altium Designer
    TerminateWithExitCode(0);
End;

Figure 5. Delphi script to programmatically generate Output Job files and close Altium Designer

Note: This script has the project path hard coded in it. This Altium forum post provides an example of how to do self discover the project’s own path.

Step 3: Set up Altium Designer to run via command line using the above Delphi script (or variation):

"C:\Program Files\Altium\AD19\X2.EXE" -RScriptingSystem:RunScript(ProjectName="<Path_to_PrjPcb_file>"^|ProcName="GenerateOutputFiles")

Note: Since we added the Delphi script into the Altium Designer Project we needed to point to the PrjPcb file (versus the PrjScr project containing the Delphi script).

Step 4: Create a mechanism to run your “tests.” In our case, we used the Python Unit Test Framework and generated a JUnit XML output to be loaded into Bamboo. For other build systems, such as Jenkins, your setup will vary.

Step 5: Start committing and watch the unit tests run!

Conclusion

In Continuous Integration and Deployment in ECAD we spoke about the benefit of using CI and build systems throughout your design lifecycle. In this article, we actually took you through the steps of getting this setup. While this setup does require some knowledge of build systems and basic coding skills, the information in this article gives you a good starting point for getting up and running.

Would you like to find out more about how Altium can help you with your next PCB design? Talk to an expert at Altium.

About the Author

Ari Mahpour

Ari is an engineer with broad experience in designing, manufacturing, testing, and integrating electrical, mechanical, and software systems. He is passionate about bringing design, verification, and test engineers together to work as a cohesive unit.

Follow on Linkedin More Content by Ari Mahpour
Previous Article
OnTrack Newsletter: PCB Design Zen, Component Management and Brain Food - June 2019
OnTrack Newsletter: PCB Design Zen, Component Management and Brain Food - June 2019

This month in the OnTrack Newsletter, we bring you topics PCB Design Zen and Component Management.

Next Article
The Evolution Of Simulation Technology and Crosstalk
The Evolution Of Simulation Technology and Crosstalk

Learn about crosstalk simulation here.