88
99__all__ = [
1010 'PythonDumper' ,
11+ 'Spicedumper' ,
1112]
1213
1314####################################################################################################
1415
15- import os
1616import logging
17-
18- from typing import Callable
17+ import os
18+ from collections .abc import Callable
19+ from typing import cast
1920
2021try :
21- from KiCadRW .sexp .schema import KiCadSchema , Symbol
22+ from kicadrw .sexp .schema import KiCadSchema , Symbol
2223except ImportError :
23- KiCadSchema = None
24+ KiCadSchema = None # ty: ignore[invalid-assignment]
2425
2526####################################################################################################
2627
2728_module_logger = logging .getLogger (__name__ )
2829
30+ LINESEP = os .linesep
31+
32+ type ElementHandler = Callable [[PythonDumper , Symbol ], str ]
33+
34+ ####################################################################################################
35+
36+ class BaseDumper :
37+
38+ def generic_wrapper (element : str ) -> ElementHandler :
39+ def wrapper (self , symbol ):
40+ return self .on_generic (element , symbol )
41+ return wrapper
42+
43+ def generic_model_wrapper (element : str ) -> ElementHandler :
44+ def wrapper (self , symbol ):
45+ return self .on_generic_model (element , symbol )
46+ return wrapper
47+
48+ def source (element : str ) -> ElementHandler :
49+ def wrapper (self , symbol ):
50+ return self .on_source (element , symbol )
51+ return wrapper
52+
53+ GROUND = 0
54+
55+ SYMBOL_MAP : dict [str , ElementHandler | int ] = {
56+ 'R' : generic_wrapper ('R' ),
57+ 'L' : generic_wrapper ('L' ),
58+ 'C' : generic_wrapper ('C' ),
59+ 'D' : generic_model_wrapper ('D' ),
60+ 'GND' : GROUND , # Fixme: typing is int
61+ 'V' : source ('V' ),
62+ # 'VDC': source('V'),
63+ # 'VPULSE': source('V'),
64+ }
65+
66+ ##############################################
67+
68+ def __init__ (self , kicad_schema : KiCadSchema , use_pyspice_unit : bool = False ) -> None :
69+ self ._use_pyspice_unit = use_pyspice_unit
70+ self ._code = []
71+
72+ for symbol in kicad_schema .symbols_by_reference :
73+ self ._logger .info (f"Symbol { symbol .lib_name } { symbol .reference } { symbol .simulation_device } " )
74+ handler = self .find_symbol (symbol )
75+ match handler :
76+ case None :
77+ self ._logger .warning (f"any correspondance for '{ symbol .lib_name } ' '{ symbol .reference } ' '{ symbol .simulation_device } '" )
78+ case int (): # for ground i.e. != self.GROUND
79+ pass
80+ case _:
81+ _ = handler (self , symbol )
82+ self ._code .append (_ )
83+
84+ ##############################################
85+
86+ def find_symbol (self , symbol : Symbol ) -> ElementHandler | int | None :
87+ name = symbol .simulation_device
88+ if not name :
89+ _ , name = symbol .lib_name .split (':' )
90+ return self .SYMBOL_MAP .get (name , None )
91+
92+ ##############################################
93+
94+ def __str__ (self ) -> str :
95+ return LINESEP .join (self ._code )
96+
97+ ####################################################################################################
98+
99+ class SpiceDumper (BaseDumper ):
100+
101+ _logger = _module_logger .getChild ('SpiceDumper' )
102+
103+ ##############################################
104+
105+ def _pins (self , symbol : Symbol ) -> list [int | str ]:
106+ pins : list [int | str ] = []
107+ for pin in symbol .pins :
108+ _id = cast (int | str , pin .inet .id ) # Fixme: due to None...
109+ # if _id == 0:
110+ # _id = 'GND'
111+ pins .append (_id )
112+ return pins
113+
114+ ##############################################
115+
116+ def _unit_value (self , element : str , symbol : Symbol ) -> str :
117+ return symbol .value
118+
119+ ##############################################
120+
121+ def _str_args (self , raw_args : list [str | int | float ]) -> str :
122+ args = []
123+ for arg in raw_args :
124+ # if isinstance(arg, str) and ('@' in arg or arg.startswith('circuit.')):
125+ # pass
126+ if isinstance (arg , (int , float )):
127+ arg = str (arg )
128+ args .append (arg )
129+ return ' ' .join (args )
130+
131+ ##############################################
132+
133+ def on_generic (self , element : str , symbol : Symbol ) -> str :
134+ self ._logger .info (f"Element '{ symbol .reference } ' params='{ symbol .simulation_paramaters } '" )
135+ reference = symbol .reference [len (element ):]
136+ value = self ._unit_value (element , symbol )
137+ args = [reference , * self ._pins (symbol ), value ]
138+ args_str = self ._str_args (args ) # ty: ignore[invalid-argument-type]
139+ return f"{ element } { args_str } "
140+
141+ ##############################################
142+
143+ def on_generic_model (self , element : str , symbol : Symbol ) -> str :
144+ self ._logger .info (f"Element with model '{ symbol .reference } ' pins='{ symbol .simulation_pins } ' params='{ symbol .simulation_paramaters } '" )
145+ # Fixme: check XD
146+ reference = symbol .reference [len (element ):] # +1
147+ # pin_names = [_.name for _ in symbol.pins]
148+ pins = self ._pins (symbol )
149+ # match pin_names:
150+ # case ('K', 'A'):
151+ # pins = list(reversed(pins))
152+ args = [reference , * pins ]
153+ args_str = self ._str_args (args ) # ty: ignore[invalid-argument-type]
154+ model_name = f'__{ symbol .value } { reference } '
155+ lines = [
156+ f".model { model_name } { element } { symbol .simulation_paramaters } " ,
157+ f"{ element } { args_str } { model_name } " ,
158+ ]
159+ # Fixme: __str__ join
160+ return LINESEP .join (lines )
161+
162+ ##############################################
163+
164+ def on_source (self , element : str , symbol : Symbol ) -> str :
165+ self ._logger .info (f"Source '{ symbol .simulation_device } ' type='{ symbol .simulation_type } ' params='{ symbol .simulation_paramaters } '" )
166+ reference = symbol .reference [len (element ):]
167+ args = [reference , * self ._pins (symbol )]
168+ args_str = self ._str_args (args ) # ty: ignore[invalid-argument-type]
169+ return f"{ element } { args_str } { symbol .simulation_type } ( { symbol .simulation_paramaters } )"
170+
29171####################################################################################################
30172
31173class PythonDumper :
32174
33175 _logger = _module_logger .getChild ('PythonDumper' )
34176
35- def generic_wrapper (element ) :
177+ def generic_wrapper (element : str ) -> ElementHandler :
36178 def wrapper (self , symbol ):
37179 return self .on_generic (element , symbol )
38180 return wrapper
39181
40- def generic_model_wrapper (element ) :
182+ def generic_model_wrapper (element : str ) -> ElementHandler :
41183 def wrapper (self , symbol ):
42184 return self .on_generic_model (element , symbol )
43185 return wrapper
44186
45- def source (element ) :
187+ def source (element : str ) -> ElementHandler :
46188 def wrapper (self , symbol ):
47189 return self .on_source (element , symbol )
48190 return wrapper
@@ -80,59 +222,62 @@ def wrapper(self, symbol):
80222 # 'spice-ngspice:ZENOR': None,
81223 # }
82224
83- SYMBOL_MAP = {
225+ SYMBOL_MAP : dict [ str , ElementHandler | int ] = {
84226 'R' : generic_wrapper ('R' ),
85227 'L' : generic_wrapper ('L' ),
86228 'C' : generic_wrapper ('C' ),
87229 'D' : generic_model_wrapper ('D' ),
88- 'GND' : GROUND ,
230+ 'GND' : GROUND , # Fixme: typing is int
89231 'V' : source ('V' ),
90232 # 'VDC': source('V'),
91233 # 'VPULSE': source('V'),
92234 }
93235
94236 ##############################################
95237
96- def __init__ (self , kicad_schema : KiCadSchema , use_pyspice_unit = False ):
238+ def __init__ (self , kicad_schema : KiCadSchema , use_pyspice_unit : bool = False ) -> None :
97239 self ._use_pyspice_unit = use_pyspice_unit
98240 self ._code = []
99241
100242 for symbol in kicad_schema .symbols_by_reference :
101243 self ._logger .info (f"Symbol { symbol .lib_name } { symbol .reference } { symbol .simulation_device } " )
102244 handler = self .find_symbol (symbol )
103- if handler is None :
104- self ._logger .warning (f"any correspondance for { symbol .lib_name } { symbol .reference } { symbol .simulation_device } " )
105- elif handler != self .GROUND :
106- _ = handler (self , symbol )
107- self ._code .append (_ )
245+ match handler :
246+ case None :
247+ self ._logger .warning (f"any correspondance for '{ symbol .lib_name } ' '{ symbol .reference } ' '{ symbol .simulation_device } '" )
248+ case int (): # for ground i.e. != self.GROUND
249+ pass
250+ case _:
251+ _ = handler (self , symbol )
252+ self ._code .append (_ )
108253
109254 ##############################################
110255
111- def find_symbol (self , symbol : Symbol ) -> Callable :
256+ def find_symbol (self , symbol : Symbol ) -> ElementHandler | int | None :
112257 name = symbol .simulation_device
113- if name is None :
258+ if not name :
114259 _ , name = symbol .lib_name .split (':' )
115260 return self .SYMBOL_MAP .get (name , None )
116261
117262 ##############################################
118263
119- def __str__ (self ):
120- return os . linesep .join (self ._code )
264+ def __str__ (self ) -> str :
265+ return LINESEP .join (self ._code )
121266
122267 ##############################################
123268
124- def _pins (self , symbol ) :
125- pins = []
269+ def _pins (self , symbol : Symbol ) -> list [ int | str ] :
270+ pins : list [ int | str ] = []
126271 for pin in symbol .pins :
127- _id = pin .net .id
272+ _id = cast ( int | str , pin .inet .id ) # Fixme: due to None...
128273 if _id == 0 :
129274 _id = 'circuit.gnd'
130275 pins .append (_id )
131276 return pins
132277
133278 ##############################################
134279
135- def _unit_value (self , element , symbol ) :
280+ def _unit_value (self , element : str , symbol : Symbol ) -> str :
136281 value = symbol .value
137282 if not self ._use_pyspice_unit :
138283 return value
@@ -150,7 +295,7 @@ def _unit_value(self, element, symbol):
150295
151296 ##############################################
152297
153- def _str_args (self , raw_args ) :
298+ def _str_args (self , raw_args : list [ str | int | float ]) -> str :
154299 args = []
155300 for arg in raw_args :
156301 if isinstance (arg , str ) and ('@' in arg or arg .startswith ('circuit.' )):
@@ -165,17 +310,17 @@ def _str_args(self, raw_args):
165310
166311 ##############################################
167312
168- def on_generic (self , element , symbol ) :
313+ def on_generic (self , element : str , symbol : Symbol ) -> str :
169314 self ._logger .info (f"Element { symbol .reference } { symbol .simulation_paramaters } " )
170315 reference = symbol .reference [len (element ):]
171316 value = self ._unit_value (element , symbol )
172317 args = [reference , * self ._pins (symbol ), value ]
173- args_str = self ._str_args (args )
318+ args_str = self ._str_args (args ) # ty: ignore[invalid-argument-type]
174319 return f"circuit.{ element } ({ args_str } )"
175320
176321 ##############################################
177322
178- def on_generic_model (self , element , symbol ) :
323+ def on_generic_model (self , element : str , symbol : Symbol ) -> str :
179324 self ._logger .info (f"Element with model { symbol .reference } { symbol .simulation_pins } { symbol .simulation_paramaters } " )
180325 # Fixme: check XD
181326 reference = symbol .reference [len (element ):] # +1
@@ -185,28 +330,28 @@ def on_generic_model(self, element, symbol):
185330 case ('K' , 'A' ):
186331 pins = list (reversed (pins ))
187332 args = [reference , * pins ]
188- args_str = self ._str_args (args )
333+ args_str = self ._str_args (args ) # ty: ignore[invalid-argument-type]
189334 return f"circuit.{ element } ({ args_str } , model='{ symbol .value } ')"
190335
191336 ##############################################
192337
193- def on_source (self , element , symbol ) :
338+ def on_source (self , element : str , symbol : Symbol ) -> str :
194339 self ._logger .info (f"Source { symbol .simulation_device } { symbol .simulation_type } { symbol .simulation_paramaters } " )
195340 reference = symbol .reference [len (element ):]
196341 match symbol .simulation_type .upper ():
197342 case 'PULSE' :
198343 element = 'PulseVoltageSource'
199344 args = [reference , * self ._pins (symbol )]
200345 params = ''
201- if symbol .simulation_paramaters is not None :
346+ if symbol .simulation_paramaters :
202347 sep = ', '
203348 params = sep .join (symbol .simulation_paramaters .split (' ' ))
204349 else :
205350 value = self ._unit_value (element , symbol )
206351 if symbol .reference [0 ] in ('V' ,):
207352 value += '@u_V'
208353 args .append (value )
209- args_str = self ._str_args (args )
354+ args_str = self ._str_args (args ) # ty: ignore[invalid-argument-type]
210355 if params :
211356 params = sep + params
212357 return f"circuit.{ element } ({ args_str } { params } )"
0 commit comments