Skip to content

Instantly share code, notes, and snippets.

@ravngr
Last active November 3, 2025 21:07
Show Gist options
  • Select an option

  • Save ravngr/fd43d578277f03312e4da7ee7fe7f8f1 to your computer and use it in GitHub Desktop.

Select an option

Save ravngr/fd43d578277f03312e4da7ee7fe7f8f1 to your computer and use it in GitHub Desktop.
This is an Altium DelphiScript that creates pin functions from a CSV file.
// Convert CSV to Altium pin functions.
// Contributors: Chris Harrison, René HENKE
Procedure CSV2Functions;
Var
SchLib: ISch_Lib;
SchComponent: ISch_Component;
OpenDialog: TOpenDialog;
PinList: TStringList;
PinEntry : string;
CSVFile: File;
CSVLine, PinName, PinPropList, PinFunctions: string;
i, j, DelimiterPosName, DelimiterPosFct, DelimiterPos: Integer;
PinIterator: ISch_Iterator;
PinItem: ISch_Line;
NoOfEntrys : Integer;
Begin
// Get current document
SchLib := SchServer.GetCurrentSchDocument;
if SchLib = Nil Then
begin
ShowError('Script must be run from an SchLib document.');
Exit;
end;
if (SchLib.ObjectID <> eSchLib) Then
begin
ShowError('Document is not an SchLib.');
Exit;
end;
SchComponent := SchLib.CurrentSchComponent;
if SchComponent = nil then
begin
ShowError('No schematic symbol currently open.');
Exit;
end;
// Prompt for CSV file
OpenDialog := TOpenDialog.Create(nil);
try
OpenDialog.Filter := 'CSV Files|*.csv|All Files|*.*';
OpenDialog.Title := 'Select CSV File';
if not OpenDialog.Execute then
begin
ShowError('No CSV file selected.');
Exit;
end;
// Initialize the pin list
PinList := TStringList.Create;
try
// Open CSV file
try
AssignFile(CSVFile, OpenDialog.FileName);
Reset(CSVFile);
except
Raise('Error opening file: ' + OpenDialog.FileName);
end;
// Parse CSV
while not Eof(CSVFile) do
begin
Readln(CSVFile, CSVLine);
DelimiterPos := Pos(',', CSVLine);
if DelimiterPos > 0 then
begin
// Append to lis
PinList.Add(AnsiReplaceText(CSVLine, ',', '/'));
end;
end;
// Close the CSV file
CloseFile(CSVFile);
// Iterate through component pins
PinIterator := SchComponent.SchIterator_Create;
PinIterator.AddFilter_ObjectSet(MkSet(ePin));
PinItem := PinIterator.FirstSchObject;
while PinItem <> Nil Do
begin
// PinItem.Name
PinName := PinItem.GetState_Designator;
for j := 0 to PinList.Count - 1 do
begin
PinEntry := PinList[j];
if StartsText(PinName + '/', PinList[j]) then
begin
DelimiterPosName := Pos('/', PinList[j]);
PinPropList := Copy(PinList[j], DelimiterPosName + 1, Length(PinList[j]) - DelimiterPosName);
DelimiterPosFct := Pos('/', PinPropList);
PinName := Copy(PinPropList, 1, DelimiterPosFct-1);
PinFunctions := Copy(PinPropList, DelimiterPosFct + 1, Length(PinPropList) - DelimiterPosFct);
if AnsiEndsStr('/', PinFunctions) then
PinFunctions := Copy(PinFunctions, 1, Length(PinFunctions) - 1);
PinItem.SetState_Name(PinFunctions + '/');
PinItem.SetState_FunctionsFromName;
PinItem.SetState_Name(PinName);
PinItem.GraphicallyInvalidate;
break;
end;
end;
PinItem := PinIterator.NextSchObject;
end;
SchComponent.SchIterator_Destroy(PinIterator);
SchLib.GraphicallyInvalidate;
SchServer.ProcessControl.PreProcess(SchLib, '');
SchServer.ProcessControl.PostProcess(SchLib, '');
ShowMessage('Pin functions updated successfully.');
finally
PinList.Free;
end;
finally
OpenDialog.Free;
end;
End;
@FloHomi
Copy link

FloHomi commented Aug 13, 2025

Hi There,
I forked your script and made a lots of comments to make it more understandable.
Also I made it so that if there is only one Function behind the designator it will take that for the name and adds no functions. before it was that it will add no name and one function.
Sadly i did not figure out how to clear all functions (have none, if there was one before) it can only overwrite all of them, if you add at least a single new one... sucks...
I love the PIN functions, but is so badly implemented :(

@FloHomi
Copy link

FloHomi commented Aug 13, 2025

Feel free to use the changed one on your site :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment