Script Example Analysis
Aby zapewnić dodatkowy wgląd w ogólne aspekty systemu skryptów oraz w użycie modeli obiektowych Delphi i X2 w skryptach, z perspektywy funkcjonalności omówiono tutaj dwa przykładowe projekty – kopiowanie obrysu płytki oraz skrypt generujący netlistę.
Skrypty Board Outline Copier i Netlister zostały opracowane z użyciem modeli obiektowych X2, aby zilustrować możliwości systemu skryptów w Altium Designer. Są to istniejące skrypty dostępne w kolekcji przykładowych skryptów w następującej postaci:
-
Skrypt Board Outline Copier wykorzystuje model obiektowy PCB do skopiowania istniejącego obrysu płytki PCB jako ścieżek i łuków na wskazaną warstwę.
Zobacz\Scripts\VB Scripts\CopyBoardOutlinePRJ.PRJSCR. -
Skrypt generatora netlisty wykorzystuje model obiektowy WorkSpace Manager do wygenerowania netlisty w tradycyjnym formacie Protel (v1 i v2).
Zobacz\Scripts\Delphiscript Scripts\WSM\Protel Netlister\ScripterProtelNetlist.PRJSCR.
Projekt Board Outline Copier
Celem Board Outline Copier jest skopiowanie istniejącego obrysu płytki z dokumentu PCB na inną warstwę w tym samym dokumencie.
Projekt wykorzystuje formularz skryptu (Script Form), aby użytkownik mógł w oknie dialogowym określić szerokość obrysu płytki i wybrać warstwę docelową z listy rozwijanej. Z użyciem modelu obiektowego PCB oraz jego interfejsów PCB z PCB API obiekty obrysu płytki są wyodrębniane i kopiowane na wskazaną warstwę.
Główne części skryptu to:
-
Globalna zmienna
PCB_Board(typuIPCB_Board). -
Procedura
CopyBoardOutline, która przyjmuje parametryAWidthiALayer. -
Procedura obsługi zdarzenia
bOkClick, która pobiera wartości szerokości i warstwy z formularza skryptu, a następnie uruchamia proceduręCopyBoardOutline. -
Procedura obsługi zdarzenia
bCancelClick, która zamyka formularz (okno dialogowe) skryptu Board Outline.
Funkcjonalność skryptu
Skrypt używa formularza, który wymaga procedur obsługi zdarzeń do przechwytywania kliknięć myszy na poszczególnych kontrolkach, takich jak przyciski OK i Cancel.
Procedura obsługi zdarzenia przycisku OK wygląda zasadniczo jak poniżej:
Sub bOKClick(Sender) Dim Width Dim Layer Call StringToCoordUnit(eWidth.Text,Width,PCB_Board.DisplayUnit) Layer = String2Layer(cbLayers.Items(cbLayers.ItemIndex)) End Sub
Tutaj procedura obsługi zdarzenia myszy formularza OnClick (bOKClick) używa funkcji StringToCoordUnit, aby uzyskać wprowadzoną szerokość obrysu (ciąg eWidth z pola TEdit) w wewnętrznych wartościach współrzędnych. Funkcja ta stosuje bieżące jednostki płytki (właściwość PCB_Board.DisplayUnit) do zmiennej Width.
Podobnie, wybrany ciąg warstwy (element cbLayers z kontrolki TComboBox formularza) jest przekazywany do funkcji String2Layer, aby uzyskać wartość wyliczeniową dla zmiennej Layer. Zwróć uwagę, że w tym projekcie kontrolka TComboBox formularza jest wstępnie wypełniona indeksowaną listą nazw warstw (cbLayers.Items) – zobacz plik CopyBoardOutlineForm.dfm formularza, aby poznać listę warstw.
Ostatni krok w procedurze obsługi zdarzenia (bOKClick) wywołuje procedurę CopyBoardOutline z przekazanymi parametrami Width i Layer. Procedura obsługi przycisku Cancel formularza (bCancelClick) po prostu zamyka formularz.
Interfejs IPCB_Board
W procedurze obsługi przycisku OK (bOKClick) bieżąca płytka jest pobierana z interfejsu IPCB_Board poprzez IPCB_ServerInterface zwrócony przez specjalną funkcję PCBServer. Tutaj funkcja GetCurrentPCB ustawia odwołanie do bieżącej płytki w zmiennej PCB_Board.
Bieżący obrys płytki (IPC_BoardOutline) jest następnie pobierany w całym skrypcie z właściwości BoardOutline interfejsu IPCB_Board, z użyciem powyższego odwołania do płytki PCB_Board.
Przed przystąpieniem do kopiowania i tworzenia nowego obrysu obrys płytki musi zostać zainicjalizowany. Obrys – reprezentowany przez interfejs IPCB_BoardOutline – można zainicjalizować, używając metod przebudowy/walidacji tego interfejsu.
PCB_Board.BoardOutline.Invalidate PCB_Board.BoardOutline.Rebuild PCB_Board.BoardOutline.Validate
Segmenty łuków i ścieżek obrysu
Interfejs IPCB_BoardOutline, reprezentujący obrys płytki, dziedziczy po interfejsie IPCB_Group. Interfejs IPCB_Group reprezentuje obiekt grupy, który może przechowywać obiekty podrzędne. Przykładem interfejsu IPCB_Group jest poligon lub obrys płytki, ponieważ mogą one przechowywać łuki i ścieżki jako obiekty podrzędne.
Obiekt obrysu płytki przechowuje dwa różne typy segmentów – ePolySegmentLine i ePolySegmentArc, które reprezentują odpowiednio obiekt ścieżki lub łuku. Liczba segmentów jest określana przez właściwość PointCount z interfejsu IPCB_BoardOutline, która wyodrębnia każdy wierzchołek obrysu do zmiennej I dla pętli For-To-Next.
Każdy segment uzyskanego obrysu płytki jest sprawdzany pod kątem ścieżek i łuków za pomocą instrukcji If PCB_Board.BoardOutline.Segments(I).Kind = ePolySegmentLine Then. Jeśli nie jest to segment ścieżki (ePolySegmentLine), część Else instrukcji zakłada, że segment jest łukiem.
Dla każdego znalezionego segmentu, w zależności od jego typu, tworzony jest nowy obiekt ścieżki lub łuku przy użyciu funkcji PCBObjectFactory.
Funkcja PCBObjectFactory
Tworzenie nowych obiektów PCB wykorzystuje funkcję PCBObjectFactory bezpośrednio z interfejsu IPCB_ServerInterface.
'Create new Track object PCBServer.PCBObjectFactory(eTrackObject, eNoDimension, eCreate_Default) 'Create new Arc object PCBServer.PCBObjectFactory(eArcObject, eNoDimension, eCreate_Default)
Parametry funkcji PCBObjectFactory ustawiają typ obiektu (Track, Arc, Via itd.), rodzaj wymiaru (Linear, Radial itd.) oraz tryb tworzenia obiektu (z lokalnymi ustawieniami domyślnymi lub globalnymi preferencjami).
Po utworzeniu każdego obiektu ścieżki lub łuku przez procedurę PCBObjectFactory jego właściwości są inicjalizowane przez następujące dalej instrukcje dla ścieżki/łuku.
Właściwości ścieżki i łuku są reprezentowane przez odpowiadające im interfejsy IPCB_Track i IPCB_Arc, w których skrypt implementuje odpowiednie właściwości. Na przykład współrzędne nowej ścieżki są pobierane z wierzchołków segmentu obrysu źródłowego, gdzie właściwości Track.X1 i Track.Y1 reprezentują współrzędne początkowe ścieżki, a właściwości X2 i Y2 – współrzędne końcowe.
Track.X1 = PCB_Board.BoardOutline.Segments(I).vx Track.Y1 = PCB_Board.BoardOutline.Segments(I).vy Track.X2 = PCB_Board.BoardOutline.Segments(J).vx Track.Y2 = PCB_Board.BoardOutline.Segments(J).vy Track.Layer = ALayer Track.Width = AWidth
Jak widać również w powyższym fragmencie kodu, właściwości Layer i Width ścieżki są po prostu definiowane przez przekazane wartości wyodrębnione z okna dialogowego interfejsu użytkownika – zmienne cbLayers i eWidth formularza.
Po pełnym zdefiniowaniu nowe obiekty są dodawane do wskazanej warstwy dokumentu PCB za pomocą instrukcji PCB_Board.AddPCBObject(NewObject), gdzie NewObject oznacza tutaj Track lub Arc.
PreProcess i PostProcess
Podczas tworzenia obiektu PCB należy najpierw wywołać metodę PreProcess z interfejsu obiektu IPCB_ServerInterface, aby przygotować serwer PCB. Po utworzeniu obiektu stosuje się metodę PostPocess (również z interfejsu IPCB_ServerInterface), aby poinformować serwer, że dodawanie obiektów zostało zakończone.
Metody PreProcess i PostProcess utrzymują system Undo oraz inne podsystemy edytora PCB na bieżąco i w synchronizacji. Poniżej przedstawiono reprezentatywny fragment kodu z instrukcjami PreProcess i PostProcess.
PCBServer.PreProcess 'Create PCB objects PCBServer.PostProcess
Gdy obiekty są dodawane do wskazanej warstwy, która nie była wyświetlana w dokumencie PCB, należy wymusić jej widoczność. Jest to obsługiwane przez instrukcję PCB_Board.LayerIsDisplayed(ALayer) = True, gdzie ALayer to warstwa wybrana przez użytkownika.
Odświeżenie dokumentu
Na koniec dokument PCB z nowym obrysem płytki jest odświeżany poleceniem PCB:Zoom i powiązanymi parametrami Action = Redraw. Parametry polecenia powiększenia (zoom) są stosowane za pomocą procedury AddStringParameter po uprzednim wyczyszczeniu bufora parametrów metodą ResetParameters.
Projekt Netlister
Celem tego projektu skryptu Netlister jest wygenerowanie standardowej netlisty Protel (w formacie Version 1 lub Version 2) dla projektu Altium Designer zawierającego schematy. Spłaszczona netlista projektu schematycznego jest podzielona na dwie sekcje:
- Oznaczenia elementów (designatory) oraz informacje powiązane z każdym elementem,
- Nazwy sieci oraz informacje powiązane z każdą nazwą sieci, wraz z połączeniami pinów (pinami elementu).
Model obiektowy WorkSpace Manager w API udostępnia interfejsy reprezentujące projekt i jego składowe – dokumenty, elementy i ich piny oraz sieci. WorkSpace Manager jest serwerem systemowym ściśle powiązanym z modułem Client, który obsługuje projekty i powiązane z nimi dokumenty. Zapewnia kompilację, obsługę projektów wieloarkuszowych, narzędzia nawigacji po łączności, obsługę wielokanałową, wiele dokumentów implementacyjnych itd. Aby uzyskać interfejs WorkSpace Manager, wywołaj funkcję GetWorkspace, która zwraca interfejs IWorkspace.
Dla skryptu Netlister interesujące są interfejsy IWorkSpace, IProject, IDocument, IComponent oraz INet.
Zwróć uwagę, że niektóre interfejsy, zwłaszcza interfejsy obiektów projektowych (design object), odpowiadają równoważnym interfejsom obiektów schematu (Schematic Object). Wynika to z faktu, że dokumenty logiczne w projekcie są dokumentami schematycznymi z informacją o łączności. W istocie zamiast WorkSpace Manager można użyć modelu Schematic Object, jednak ten pierwszy zapewnia funkcje kompilacji projektu i wyodrębniania dokumentów z projektu, a także pobierania danych z obiektów schematu.
Główne części skryptu Netlister to:
-
Globalna zmienna łańcuchowa
TargetFileName, która jest nazwą pliku netlisty. -
Globalny obiekt kolekcji Netlist
TStringList, który jest wypełniany danymi netlisty. -
Procedury
WriteComponent_Version1iWriteComponent_Version2. -
Procedury
WriteNet_Version1iWriteNet_Version2. -
Funkcja
ConvertElectricToString, która konwertuje właściwość elektryczną pinu na łańcuch znaków -
Procedura
GenerateNetlist, która zarządza generowaniem danych oraz zadaniami porządkowymi związanymi z nazwą pliku, ścieżką i katalogiem.
Funkcjonalność skryptu
Dwie bezparametrowe procedury, GenerateProtelV1FormatNetlist i GenerateProtelV2FormatNetlist, pojawią się w oknie dialogowym Select Item to Run dialog, oferując wybór wygenerowania netlisty w formacie Protel V1 lub Protel V2. Procedury te wywołują procedurę GenerateNetlist, przekazując jako parametr wybór formatu netlisty (0 lub 1).
Procedure GenerateProtelV1FormatNetlist; Var Version : Integer; Begin // Protel 1 Netlist format, pass 0 GenerateNetlist(0); End; Procedure GenerateProtelV2FormatNetlist; Var Version : Integer; Begin // Protel 2 Netlist format, pass 1 GenerateNetlist(1); End;
GenerateNetList
Procedura GenerateNetList pobiera interfejs workspace, aby następnie można było wyodrębnić interfejs projektu dla bieżącego projektu (IWorkspace.DM_FocusedProject).
Projekt musi zostać skompilowany, zanim będzie można wyodrębnić sieci, ponieważ proces kompilacji buduje informację o łączności projektu. Zastosowana jest metoda DM_Compile interfejsu projektu (IProject.DM_Compile), jak pokazano w poniższym fragmencie kodu. Zwróć uwagę, że nowsze wersje Altium Designer kompilują projekty automatycznie, więc ten krok jest opcjonalny.
WS := GetWorkspace; If WS = Nil Then Exit; Prj := WS.DM_FocusedProject; If Prj = Nil Then Exit; // Compile the project to fetch the connectivity info for design. Prj.DM_Compile;
Informacje o elementach i sieciach są przechowywane w obiekcie Netlist typu TStringList, który jest później używany do wygenerowania sformatowanego tekstowego pliku netlisty. Obiekt TStringList jest klasą Delphi dostępną do użycia w skryptach.
Następnie wywoływana jest procedura Generate z przekazanymi parametrami definiującymi ścieżkę i nazwę pliku bieżącego projektu oraz wersję formatu netlisty.
Generate
Procedura Generate pobiera ścieżkę projektu jako docelową ścieżkę wyjściową dla generowanego pliku netlisty (z przekazanego parametru DocumentPath), określa nazwę pliku netlisty (TargetFileName) i sprawdza status spłaszczenia projektu (IProject.DM_DocumentFlattened).
Dla wszystkich dokumentów schematycznych w projekcie każdy dokument jest następnie sprawdzany pod kątem sieci i elementów za pomocą procedur WriteNets i WriteComponents, a ostatecznie wyodrębniany do obiektu Netlist.
Zapis sieci i elementów
Netlista składa się z sekcji elementów i sekcji sieci, dlatego potrzebne są dwie procedury do osobnego zapisu danych elementów i danych sieci.
Do netlisty zostaną zapisane tylko sieci mające więcej niż dwa węzły, a te z mniejszą liczbą zostaną odrzucone. Dla każdej sieci nazwa sieci jest oparta na metodzie DM_CalculatedNetName obiektu Net, która wyodrębnia nazwy sieci z informacji o łączności skompilowanego projektu.
Poniżej pokazano dwa fragmenty kodu dla sekcji Components i Nets netlisty w formacie Version 1. Zwróć uwagę, że dane elementów i sieci są przechowywane w obiekcie NetList typu TStringList. Wygenerowana netlista składa się z dwóch sekcji: sekcji informacji o elementach oraz sekcji informacji o sieciach.
Sekcja Components
W procedurze WriteComponent każdy element znaleziony w projekcie jest sprawdzany, czy jest rzeczywistym elementem, a następnie wyodrębniane są wartości: oznaczenie fizyczne (physical designator), footprint oraz typ części (part type). Są one dodawane do kontenera obiektu Netlist (NetList.Add), aby zbudować samą netlistę.
If Component <> Nil Then
Begin
NetList.Add('[');
NetList.Add(Component.DM_PhysicalDesignator);
NetList.Add(Component.DM_FootPrint);
NetList.Add(Component.DM_PartType);
NetList.Add('');
NetList.Add('');
NetList.Add('');
NetList.Add(']');
End;
Sekcja Nets
Dla procedury Nets nazwa sieci (NetName) oraz designatory są wyodrębniane, jeśli sieć ma co najmniej dwa piny (INet.DM_PinCount). Informacje o sieci i pinach oraz znaki formatujące są dodawane do kontenera Netlist, aby zbudować netlistę. Poniższy fragment to procedura zapisu sieci dla netlisty w wersji 1.
If Net.DM_PinCount >= 2 Then
Begin
NetList.Add('(');
NetList.Add(Net.DM_CalculatedNetName);
For i := 0 To Net.DM_PinCount – 1 Do
Begin
Pin := Net.DM_Pins(i);
PinDsgn := Pin.DM_PhysicalPartDesignator;
PinNo := Pin.DM_PinNumber;
NetList.Add(PinDsgn + '-' + PinNo);
End;
NetList.Add(')');
End;
Zwróć uwagę, że bardziej rozbudowany format netlisty, Protel v2, zawiera właściwości elektryczne pinów sieci (In, Out, Passive, HiZ itd.).
Procedura zapisu sieci dla formatu w wersji 2 (WriteNet_Version2) odczytuje więc właściwość elektryczną każdego pinu sieci (INet.DM_Electical), która następnie jest konwertowana przez wywołaną procedurę ConvertElectricToString – w praktyce jest to tablica wyszukiwania do konwersji na łańcuch znaków. Następnie są one dodawane do lokalnej zmiennej łańcuchowej (ElectricalString), która z kolei jest dodawana do obiektu kontenera Netlist.
Utworzenie pliku netlisty
Na koniec, gdy obiekt kontenera Netlist jest w pełni wypełniony informacjami o elementach i sieciach projektu w wybranym formacie, procedura Generate zapisuje dane Netlist do pliku (TStringList.SaveToFile). Ścieżka i nazwa pliku są zdefiniowane przez zmienną łańcuchową TargetFileName, zgodnie z ustaleniami w procedurze Generate.


