Skip to content

Commit 9557e67

Browse files
committed
basic documentation
1 parent 2eabfe1 commit 9557e67

File tree

1 file changed

+260
-2
lines changed

1 file changed

+260
-2
lines changed

README.md

Lines changed: 260 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,260 @@
1-
# psychogenic-eeschema
2-
eeschema schematic manipulation
1+
# kicad skip: S-expression kicad file python parser
2+
3+
Copyright © 2024 Pat Deegan, [psychogenic.com](https://psychogenic.com/)
4+
5+
6+
This library is focused on scripted manipulations of schematics (and other) kicad _source_ _files_
7+
and allows any item to be edited in a hopefully intuitive way.
8+
9+
It also provides helpers for common operations.
10+
11+
12+
Kicad schematic, layout and other files are stored as trees of s-expressions, like
13+
14+
```
15+
(kicad_sch (version 20230121) (generator eeschema)
16+
(uuid 20adca1d-43a1-4784-9682-8b7dd1c7d330)
17+
(title_block (title "My Demo Board") (date "2024-01-31") (rev "1.0.5")
18+
(company "Psychogenic Technologies") (comment 1 "(C) 2023, 2024 Pat Deegan")
19+
)
20+
(lib_symbols
21+
(symbol "74xx:74CBTLV3257" (in_bom yes) (on_board yes)
22+
(property "Reference" "U" (at 17.78 1.27 0) (effects (font (size 1.27 1.27))))
23+
(property "Value" "74CBTLV3257" (at 15.24 -1.27 0)(effects (font (size 1.27 1.27))))
24+
...
25+
(symbol (lib_id "SomeLib:Partname") (at 317.5 45.72 0) (unit 1)
26+
(in_bom yes) (on_board yes) (dnp no)
27+
(uuid 342c76f3-b2b8-40b2-a0b0-d83e480188cc)
28+
(property "Reference" "J4" (at 311.15 29.21 0)(effects (font (size 1.27 1.27))))
29+
(property "Value" "TT04_BREAKOUT_REVB" (at 317.5 76.2 0) (effects (font (size 1.27 1.27))))
30+
(property "Footprint" "TinyTapeout:TT04_BREAKOUT_SMB" (at 320.04 81.28 0)
31+
(effects (font (size 1.27 1.27)) hide))
32+
(pin "A1" (uuid 5132b98d-ec39-4a2b-974d-c4d323ea43eb))
33+
(pin "A10" (uuid bf1f9b27-0b93-4778-ac69-684e16bea09c))
34+
(pin "A19" (uuid 43e3e4f6-008a-4ddf-a427-4414db85dcbb))
35+
...
36+
```
37+
which are great for machine parsing, but not so much for a quick scripted manipulation.
38+
39+
With skip, you can quickly explore and modify the contents of a schematic (or, really, any
40+
kicad s-expression file).
41+
42+
43+
## Examples
44+
45+
Effort has been made to make exploring the contents easy. This means:
46+
47+
#### named attributes
48+
Where possible, collections have named attributes: **do use** TAB-completion, schem.<TAB><TAB> etc
49+
50+
Examples
51+
52+
```
53+
>>> schem.symbol.U TAB TAB
54+
```
55+
outputs (something like, depending on schematic):
56+
57+
```
58+
schem.symbol.U1 schem.symbol.U3 schem.symbol.U4_B schem.symbol.U4_D
59+
schem.symbol.U2 schem.symbol.U4_A schem.symbol.U4_C schem.symbol.U4_E
60+
```
61+
62+
and
63+
64+
```
65+
>>> schem.symbol.U1.property. TAB TAB
66+
```
67+
68+
outputs
69+
70+
```
71+
schem.symbol.U1.property.Characteristics
72+
schem.symbol.U1.property.Datasheet
73+
schem.symbol.U1.property.DigikeyPN
74+
schem.symbol.U1.property.Footprint
75+
schem.symbol.U1.property.MPN
76+
schem.symbol.U1.property.Reference
77+
schem.symbol.U1.property.Value
78+
```
79+
80+
#### representation
81+
`__repr__` and `__str__` overrides so you have an idea what you're looking at. Just enter the variable in the REPL console and it should spit something sane out.
82+
83+
84+
```
85+
>>> schem
86+
<Schematic 'samp/my_schematic.kicad_sch'>
87+
88+
>>> schem.symbol[23]
89+
<symbol C28>
90+
91+
>>> schem.symbol[23].property
92+
<Collection [<PropertyString Reference = 'C28'>, <PropertyString Value = '100nF'>,
93+
<PropertyString Footprint = 'Capacitor_SMD:C_0402_1005Metric'>,
94+
<PropertyString Datasheet = '~'>, <PropertyString JLC = ''>,
95+
<PropertyString Part_number = ''>, <PropertyString MPN = 'CL05A104KA5NNNC'>,
96+
<PropertyString Characteristics = '100n 10% 25V XR 0402'>,
97+
<PropertyString MPN_ALT = 'GRM155R71E104KE14J'>]>
98+
99+
>>> schem.wire[22]
100+
<Wire [314.96, 152.4] - [317.5, 152.4]>
101+
102+
>>> schem.text[4]
103+
<text 'Options fo...'>
104+
105+
# and much more, e.g. for library symbols, junctions, labels, whatever's in there
106+
```
107+
108+
109+
## Quick walkthrough
110+
111+
Here's some sample interaction with the library. The basic functions allow you to view and edit attributes. More involved helpers let you search and crawl the schematic to find things.
112+
113+
114+
#### basic
115+
116+
```
117+
# load a schematic
118+
schem = skip.Schematic('samp/my_schem.kicad_sch')
119+
120+
# loop over all components, treat collection as array
121+
for component in schem.symbol:
122+
component # do something
123+
124+
# search through the symbols by reference or value, using regex or starts_with
125+
>>> schem.symbol.reference_matches(r'(C|R)2[158]')
126+
[<symbol C25>, <symbol C28>, <symbol R25>, <symbol C21>, <symbol R21>, <symbol R28>]
127+
128+
>>> sorted(schem.symbol.value_startswith('10k'))
129+
[<symbol R12>, <symbol R30>, <symbol R31>, <symbol R32>, <symbol R33>, <symbol R42>,
130+
<symbol R43>, <symbol R44>, <symbol R45>, <symbol R46>, <symbol R47>, <symbol R48>,
131+
<symbol R8>, <symbol R9>]
132+
133+
# or refer to components by name
134+
conn = schem.symbol.J15
135+
136+
# symbols have attributes
137+
if not conn.in_bom:
138+
conn.dnp = True
139+
140+
# and properties (things that can be named by user)
141+
for p in conn.property:
142+
print(f'{p.name} = {p.value}')
143+
# will output "Reference = J15", "MPN = USB4500-03-0-A" etc
144+
145+
# and change properties, of course
146+
>>> conn.property.MPN.value = 'ABC123'
147+
>>> conn.property.MPN
148+
<PropertyString MPN = 'ABC123'>
149+
150+
151+
152+
# clone pretty much anything and modify it
153+
>>> mpn_alt = conn.property.MPN.clone()
154+
>>> mpn_alt.name = 'MPN_ALT'
155+
>>> mpn_alt.value = 'ABC456'
156+
157+
158+
# save the result
159+
>>> schem.write('/tmp/newfile.kicad_sch')
160+
161+
# let's verify the change
162+
>>> schem.read('/tmp/newfile.kicad_sch')
163+
>>> conn = schem.symbol.J15
164+
>>> for p in conn.property:
165+
p
166+
<PropertyString Reference = 'J15'>
167+
<PropertyString Value = 'USB4500-03-0-A_REVA'>
168+
<PropertyString MPN = 'ABC123'>
169+
<PropertyString MPN_ALT = 'ABC456'>
170+
171+
```
172+
173+
174+
### Helpers
175+
176+
Collections, and the source file object, have helpers to locate relevant elements.
177+
178+
#### Attached elements
179+
180+
Where applicable, such as for symbols (components), directly attached elements (via wires)
181+
may be listed using attached_*
182+
183+
```
184+
>>> conn = sch.symbol.J15
185+
186+
>>> conn.attached_ TAB TAB
187+
conn.attached_all
188+
conn.attached_global_labels
189+
conn.attached_labels
190+
conn.attached_symbols
191+
conn.attached_wires
192+
>>> conn.attached_symbols
193+
[<symbol C3>, <symbol R16>, <symbol C47>,
194+
<symbol R20>, <symbol C46>, <symbol R21>,
195+
<symbol F1>]
196+
197+
>>> conn.attached_labels
198+
[<label CC2>, <label CC1>]
199+
200+
# or list everything attached
201+
>>> conn.attached_all
202+
[<symbol C3>, <symbol R16>, <symbol C47>,
203+
<symbol R20>, <symbol C46>, <symbol R21>,
204+
<symbol F1>, <global_label usb_d->,
205+
<global_label usb_d+>, <label CC2>,
206+
<label CC1>]
207+
208+
```
209+
210+
#### finding elements
211+
212+
Symbols may be located by reference or value
213+
214+
* schem.symbol.reference_matches(REGEX)
215+
216+
* schem.symbol.reference_startswith(STR)
217+
218+
In addition, containers with 'positionable' elements have
219+
220+
* within_circle(X, Y, RADIUS)
221+
222+
* within_rectangle(X1, Y1, X2, Y2)
223+
224+
* within_reach_of(ELEMENT, RADIUS) # circle around ELEMENT's position
225+
226+
* between_elements(ELEMENT1, ELEMENT2) # within rectangle formed by two elements
227+
228+
A collection will only return results of it's own type (e.g. global_labels.within_circle() will only return global labels).
229+
230+
To search the entire schematic, the same within* and between() methods exist on the source file object (the schem, here).
231+
This will return any label, global label or symbol with the constrained bounds.
232+
233+
```
234+
235+
>>> schem.global_label.between_elements(sch.symbol.C49, sch.symbol.R16)
236+
[<global_label usb_d->, <global_label usb_d+>,
237+
<global_label usb_d+>, <global_label usb_d->]
238+
>>>
239+
>>> schem.between_elements(sch.symbol.C49, sch.symbol.R16)
240+
[<symbol C44>, <symbol #PWR0121>, <symbol J15>,
241+
<symbol C47>, <symbol #PWR0122>, <symbol D5>, <symbol C48>,
242+
<symbol C45>, <symbol #PWR021>, <symbol C49>, <symbol R20>,
243+
<symbol C46>, <symbol #FLG02>, <symbol F1>, <symbol C3>,
244+
<symbol R16>, <symbol R21>, <symbol D6>, <label CC2>,
245+
<label CC1>, <label vfused>, <global_label usb_d->,
246+
<global_label usb_d+>, <global_label usb_d+>,
247+
<global_label usb_d->]
248+
249+
```
250+
251+
## API
252+
253+
Further documentation to come. For now, use the above, load a schematic in a console, and explore what's available using TAB-/code-completion.
254+
255+
The main thing to note is that the leaves of the tree usually have a ".value" that should be used to access the actual contents and, especially, for setting values. Have fun.
256+
257+
2024-04-04
258+
Pat Deegan
259+
260+

0 commit comments

Comments
 (0)