Skip to content

Instantly share code, notes, and snippets.

@3bagorion33
Forked from FloHomi/CSV2Functions.pas
Created December 4, 2025 12:29
Show Gist options
  • Select an option

  • Save 3bagorion33/2b2e7ef77143d84e4eadc90d45255f4a to your computer and use it in GitHub Desktop.

Select an option

Save 3bagorion33/2b2e7ef77143d84e4eadc90d45255f4a to your computer and use it in GitHub Desktop.
This is an Altium DelphiScript that creates pin functions from a CSV file.
{*******************************************************************************
* CSV2Functions - Altium Designer Script
*
* Purpose: Imports pin names and functions from a CSV file and applies them
* to the currently selected schematic component in a library.
*
* CSV Format Expected:
* - Column 1: Pin designator (e.g., "1", "A1", "B2")
* - Column 2: New pin name (e.g., "VCC", "GND", "DATA")
* - Column 3: Pin functions (e.g., "Power/Input", "Ground", "I/O")
*
* Example CSV content:
* 1,VCC,Power
* 2,GND,Ground
* 3,DATA,I/O/Digital
*
* Contributors: Chris Harrison, René HENKE
*******************************************************************************}
Procedure CSV2Functions;
Var
// Altium document and component references
SchLib: ISch_Lib; // Reference to the schematic library document
SchComponent: ISch_Component; // Reference to the current component being edited
// File handling variables
OpenDialog: TOpenDialog; // Dialog for CSV file selection
PinList: TStringList; // List to store parsed CSV entries
PinEntry: string; // Individual entry from the pin list
// CSV parsing variables
CSVFile: File; // File handle for the CSV file
CSVLine: string; // Current line being read from CSV
PinName: string; // Pin designator from the component
PinPropList: string; // Properties extracted from CSV (name + functions)
PinFunctions: string; // Pin functions extracted from CSV
NewPinName: string; // New pin name to be applied
// Loop and position tracking variables
i, j: Integer; // Loop counters
DelimiterPosName: Integer; // Position of delimiter between pin designator and name
DelimiterPosFct: Integer; // Position of delimiter between name and functions
DelimiterPos: Integer; // General delimiter position for CSV parsing
// Pin iteration variables
PinIterator: ISch_Iterator; // Iterator for traversing component pins
PinItem: ISch_Line; // Current pin being processed
NoOfEntrys: Integer; // Number of entries (currently unused)
Begin
{***************************************************************************
* STEP 1: Validate the current document and component
**************************************************************************}
// Get reference to the currently active schematic library document
SchLib := SchServer.GetCurrentSchDocument;
// Ensure we're working with a valid schematic library document
if SchLib = Nil Then
begin
ShowError('Script must be run from an SchLib document.');
Exit;
end;
// Double-check that the document is actually a schematic library
if (SchLib.ObjectID <> eSchLib) Then
begin
ShowError('Document is not an SchLib.');
Exit;
end;
// Get reference to the currently selected component in the library
SchComponent := SchLib.CurrentSchComponent;
// Ensure a component is currently selected/open for editing
if SchComponent = nil then
begin
ShowError('No schematic symbol currently open.');
Exit;
end;
{***************************************************************************
* STEP 2: Get CSV file from user
**************************************************************************}
// Create and configure file selection dialog
OpenDialog := TOpenDialog.Create(nil);
try
// Set up the file dialog to filter for CSV files
OpenDialog.Filter := 'CSV Files|*.csv|All Files|*.*';
OpenDialog.Title := 'Select CSV File';
// Show the dialog and exit if user cancels
if not OpenDialog.Execute then
begin
ShowError('No CSV file selected.');
Exit;
end;
{*************************************************************************
* STEP 3: Parse the CSV file and store pin data
************************************************************************}
// Initialize string list to store parsed CSV entries
PinList := TStringList.Create;
try
// Open the selected CSV file for reading
try
AssignFile(CSVFile, OpenDialog.FileName);
Reset(CSVFile);
except
Raise('Error opening file: ' + OpenDialog.FileName);
end;
// Read and parse each line of the CSV file
while not Eof(CSVFile) do
begin
Readln(CSVFile, CSVLine);
// Look for comma delimiter (basic CSV parsing)
DelimiterPos := Pos(',', CSVLine);
if DelimiterPos > 0 then
begin
// Convert CSV format (comma-separated) to internal format (slash-separated)
// This makes it easier to parse later: "1,VCC,Power" becomes "1/VCC/Power"
PinList.Add(AnsiReplaceText(CSVLine, ',', '/'));
end;
end;
// Close the CSV file as we're done reading
CloseFile(CSVFile);
{*********************************************************************
* STEP 4: Apply pin data to component pins
********************************************************************}
// Create iterator to traverse all pins in the component
PinIterator := SchComponent.SchIterator_Create;
PinIterator.AddFilter_ObjectSet(MkSet(ePin));
// Start iterating through each pin in the component
PinItem := PinIterator.FirstSchObject;
while PinItem <> Nil Do
begin
// Get the current pin's designator (e.g., "1", "A1", "B2")
PinName := PinItem.GetState_Designator;
// Search through our CSV data for a matching pin designator
for j := 0 to PinList.Count - 1 do
begin
PinEntry := PinList[j];
// Check if this CSV entry starts with our pin designator
// Format expected: "PinDesignator/PinName/Functions"
if StartsText(PinName + '/', PinList[j]) then
begin
// Extract everything after the pin designator
DelimiterPosName := Pos('/', PinList[j]);
PinPropList := Copy(PinList[j], DelimiterPosName + 1, Length(PinList[j]) - DelimiterPosName);
// Look for another delimiter to separate name from functions
DelimiterPosFct := Pos('/', PinPropList);
if DelimiterPosFct > 0 then
begin
// Case 1: We have both pin name AND functions
// Extract the new pin name (between first and second slash)
NewPinName := Copy(PinPropList, 1, DelimiterPosFct - 1);
// Extract the pin functions (everything after second slash)
PinFunctions := Copy(PinPropList, DelimiterPosFct + 1, Length(PinPropList) - DelimiterPosFct);
// Remove trailing slash if present
if AnsiEndsStr('/', PinFunctions) then
PinFunctions := Copy(PinFunctions, 1, Length(PinFunctions) - 1);
// Apply the functions first by setting them as the name temporarily
PinItem.SetState_Name(PinFunctions + '/');
PinItem.SetState_FunctionsFromName; // Parse functions from the name
// Then set the actual pin name
PinItem.SetState_Name(NewPinName);
end
else
begin
// Case 2: We only have a pin name, no functions specified
NewPinName := PinPropList;
// Clear any existing functions first (does not work)
PinItem.SetState_Name('');
PinItem.SetState_FunctionsFromName; // Apply empty functions
// Set the new pin name
PinItem.SetState_Name(NewPinName);
end;
// Update the visual representation of the pin
PinItem.GraphicallyInvalidate;
// Break out of the search loop as we found our match
break;
end;
end;
// Move to the next pin in the component
PinItem := PinIterator.NextSchObject;
end;
{*********************************************************************
* STEP 5: Clean up and finalize changes
********************************************************************}
// Clean up the pin iterator
SchComponent.SchIterator_Destroy(PinIterator);
// Refresh the visual display of the entire library
SchLib.GraphicallyInvalidate;
// Process the changes through Altium's change management system
SchServer.ProcessControl.PreProcess(SchLib, '');
SchServer.ProcessControl.PostProcess(SchLib, '');
// Notify user of successful completion
ShowMessage('Pin functions updated successfully.');
finally
// Always clean up the pin list, even if an error occurred
PinList.Free;
end;
finally
// Always clean up the file dialog, even if an error occurred
OpenDialog.Free;
end;
End;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment