KiCad PCB EDA Suite
net_settings.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2020 CERN
5  * @author Jon Evans <jon@craftyjon.com>
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <project/net_settings.h>
22 #include <settings/parameters.h>
24 #include <kicad_string.h>
25 #include <convert_to_biu.h>
26 
28 
29 
30 NET_SETTINGS::NET_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
31  NESTED_SETTINGS( "net_settings", netSettingsSchemaVersion, aParent, aPath ),
32  m_NetClasses()
33 {
34  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "classes",
35  [&]() -> nlohmann::json
36  {
37  nlohmann::json ret = nlohmann::json::array();
38 
39  NETCLASSPTR netclass = m_NetClasses.GetDefault();
41 
42  for( unsigned int idx = 0; idx <= m_NetClasses.GetCount(); idx++ )
43  {
44  if( idx > 0 )
45  {
46  netclass = nc->second;
47  ++nc;
48  }
49 
50  // Note: we're in common/, but we do happen to know which of these fields
51  // are used in which units system.
52  nlohmann::json netclassJson = {
53  { "name", netclass->GetName().ToUTF8() },
54  { "clearance", PcbIu2Millimeter( netclass->GetClearance() ) },
55  { "track_width", PcbIu2Millimeter( netclass->GetTrackWidth() ) },
56  { "via_diameter", PcbIu2Millimeter( netclass->GetViaDiameter() ) },
57  { "via_drill", PcbIu2Millimeter( netclass->GetViaDrill() ) },
58  { "microvia_diameter", PcbIu2Millimeter( netclass->GetuViaDiameter() ) },
59  { "microvia_drill", PcbIu2Millimeter( netclass->GetuViaDrill() ) },
60  { "diff_pair_width", PcbIu2Millimeter( netclass->GetDiffPairWidth() ) },
61  { "diff_pair_gap", PcbIu2Millimeter( netclass->GetDiffPairGap() ) },
62  { "diff_pair_via_gap", PcbIu2Millimeter( netclass->GetDiffPairViaGap() ) },
63  { "wire_width", SchIu2Mils( netclass->GetWireWidth() ) },
64  { "bus_width", SchIu2Mils( netclass->GetBusWidth() ) },
65  { "line_style", netclass->GetLineStyle() }
66  };
67 
68  if( netclass->GetPcbColor() != KIGFX::COLOR4D::UNSPECIFIED )
69  netclassJson["pcb_color"] = netclass->GetPcbColor();
70 
71  if( netclass->GetSchematicColor() != KIGFX::COLOR4D::UNSPECIFIED )
72  netclassJson["schematic_color"] = netclass->GetSchematicColor();
73 
74  if( idx > 0 )
75  {
76  nlohmann::json membersJson = nlohmann::json::array();
77 
78  for( const auto& ii : *netclass )
79  {
80  if( !ii.empty() )
81  membersJson.push_back( ii );
82  }
83 
84  netclassJson["nets"] = membersJson;
85  }
86 
87  ret.push_back( netclassJson );
88  }
89 
90  return ret;
91  },
92  [&]( const nlohmann::json& aJson )
93  {
94  if( !aJson.is_array() )
95  return;
96 
98  m_NetClassAssignments.clear();
99  NETCLASSPTR netclass;
100  NETCLASSPTR defaultClass = m_NetClasses.GetDefault();
101 
102  auto getInPcbUnits =
103  []( const nlohmann::json& aObj, const std::string& aKey, int aDefault )
104  {
105  if( aObj.contains( aKey ) )
106  return PcbMillimeter2iu( aObj[aKey].get<double>() );
107  else
108  return aDefault;
109  };
110 
111  auto getInSchematicUnits =
112  []( const nlohmann::json& aObj, const std::string& aKey, int aDefault )
113  {
114  if( aObj.contains( aKey ) )
115  return SchMils2iu( aObj[aKey].get<double>() );
116  else
117  return aDefault;
118  };
119 
120  for( const nlohmann::json& entry : aJson )
121  {
122  if( !entry.is_object() || !entry.contains( "name" ) )
123  continue;
124 
125  wxString name = entry["name"];
126 
127  if( name == defaultClass->GetName() )
128  netclass = defaultClass;
129  else
130  netclass = std::make_shared<NETCLASS>( name );
131 
132  netclass->SetClearance( getInPcbUnits( entry, "clearance",
133  netclass->GetClearance() ) );
134  netclass->SetTrackWidth( getInPcbUnits( entry, "track_width",
135  netclass->GetTrackWidth() ) );
136  netclass->SetViaDiameter( getInPcbUnits( entry, "via_diameter",
137  netclass->GetViaDiameter() ) );
138  netclass->SetViaDrill( getInPcbUnits( entry, "via_drill",
139  netclass->GetViaDrill() ) );
140  netclass->SetuViaDiameter( getInPcbUnits( entry, "microvia_diameter",
141  netclass->GetuViaDiameter() ) );
142  netclass->SetuViaDrill( getInPcbUnits( entry, "microvia_drill",
143  netclass->GetuViaDrill() ) );
144  netclass->SetDiffPairWidth( getInPcbUnits( entry, "diff_pair_width",
145  netclass->GetDiffPairWidth() ) );
146  netclass->SetDiffPairGap( getInPcbUnits( entry, "diff_pair_gap",
147  netclass->GetDiffPairGap() ) );
148  netclass->SetDiffPairViaGap( getInPcbUnits( entry, "diff_pair_via_gap",
149  netclass->GetDiffPairViaGap() ) );
150  netclass->SetWireWidth( getInSchematicUnits( entry, "wire_width",
151  netclass->GetWireWidth() ) );
152  netclass->SetBusWidth( getInSchematicUnits( entry, "bus_width",
153  netclass->GetWireWidth() ) );
154 
155  if( entry.contains( "line_style" ) && entry["line_style"].is_number() )
156  netclass->SetLineStyle( entry["line_style"].get<int>() );
157 
158  if( entry.contains( "nets" ) && entry["nets"].is_array() )
159  {
160  for( const auto& net : entry["nets"].items() )
161  netclass->Add( net.value().get<wxString>() );
162  }
163 
164  if( entry.contains( "pcb_color" ) && entry["pcb_color"].is_string() )
165  netclass->SetPcbColor( entry["pcb_color"].get<KIGFX::COLOR4D>() );
166 
167  if( entry.contains( "schematic_color" ) && entry["schematic_color"].is_string() )
168  netclass->SetSchematicColor( entry["schematic_color"].get<KIGFX::COLOR4D>() );
169 
170  if( netclass != defaultClass )
171  m_NetClasses.Add( netclass );
172 
173  for( const wxString& net : *netclass )
174  m_NetClassAssignments[ net ] = netclass->GetName();
175  }
176 
178  },
179  {} ) );
180 
181  m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "net_colors",
182  [&]() -> nlohmann::json
183  {
184  nlohmann::json ret = {};
185 
186  for( const auto& pair : m_PcbNetColors )
187  {
188  std::string key( pair.first.ToUTF8() );
189  ret[key] = pair.second;
190  }
191 
192  return ret;
193  },
194  [&]( const nlohmann::json& aJson )
195  {
196  if( !aJson.is_object() )
197  return;
198 
199  m_PcbNetColors.clear();
200 
201  for( const auto& pair : aJson.items() )
202  {
203  wxString key( pair.key().c_str(), wxConvUTF8 );
204  m_PcbNetColors[key] = pair.value().get<KIGFX::COLOR4D>();
205  }
206  },
207  {} ) );
208 }
209 
210 
212 {
213  // Release early before destroying members
214  if( m_parent )
215  {
217  m_parent = nullptr;
218  }
219 }
220 
221 
222 static bool isSuperSub( wxChar c )
223 {
224  return c == '_' || c == '^';
225 };
226 
227 
228 bool NET_SETTINGS::ParseBusVector( const wxString& aBus, wxString* aName,
229  std::vector<wxString>* aMemberList )
230 {
231  auto isDigit = []( wxChar c )
232  {
233  static wxString digits( wxT( "0123456789" ) );
234  return digits.Contains( c );
235  };
236 
237  size_t busLen = aBus.length();
238  size_t i = 0;
239  wxString prefix;
240  wxString suffix;
241  wxString tmp;
242  long begin = 0;
243  long end = 0;
244  int braceNesting = 0;
245 
246  prefix.reserve( busLen );
247 
248  // Parse prefix
249  //
250  for( ; i < busLen; ++i )
251  {
252  if( aBus[i] == '{' )
253  {
254  if( i > 0 && isSuperSub( aBus[i-1] ) )
255  braceNesting++;
256  else
257  return false;
258  }
259  else if( aBus[i] == '}' )
260  {
261  braceNesting--;
262  }
263 
264  if( aBus[i] == ' ' || aBus[i] == ']' )
265  return false;
266 
267  if( aBus[i] == '[' )
268  break;
269 
270  prefix += aBus[i];
271  }
272 
273  // Parse start number
274  //
275  i++; // '[' character
276 
277  if( i >= busLen )
278  return false;
279 
280  for( ; i < busLen; ++i )
281  {
282  if( aBus[i] == '.' && i + 1 < busLen && aBus[i+1] == '.' )
283  {
284  tmp.ToLong( &begin );
285  i += 2;
286  break;
287  }
288 
289  if( !isDigit( aBus[i] ) )
290  return false;
291 
292  tmp += aBus[i];
293  }
294 
295  // Parse end number
296  //
297  tmp = wxEmptyString;
298 
299  if( i >= busLen )
300  return false;
301 
302  for( ; i < busLen; ++i )
303  {
304  if( aBus[i] == ']' )
305  {
306  tmp.ToLong( &end );
307  ++i;
308  break;
309  }
310 
311  if( !isDigit( aBus[i] ) )
312  return false;
313 
314  tmp += aBus[i];
315  }
316 
317  // Parse suffix
318  //
319  for( ; i < busLen; ++i )
320  {
321  if( aBus[i] == '}' )
322  {
323  braceNesting--;
324  suffix += aBus[i];
325  }
326  else if( aBus[i] == '~' )
327  {
328  suffix += aBus[i];
329  }
330  else
331  {
332  return false;
333  }
334  }
335 
336  if( braceNesting != 0 )
337  return false;
338 
339  if( begin == end )
340  return false;
341  else if( begin > end )
342  std::swap( begin, end );
343 
344  if( aName )
345  *aName = prefix;
346 
347  if( aMemberList )
348  {
349  for( long idx = begin; idx <= end; ++idx )
350  {
351  wxString str = prefix;
352  str << idx;
353  str << suffix;
354 
355  aMemberList->emplace_back( str );
356  }
357  }
358 
359  return true;
360 }
361 
362 
363 bool NET_SETTINGS::ParseBusGroup( wxString aGroup, wxString* aName,
364  std::vector<wxString>* aMemberList )
365 {
366  size_t groupLen = aGroup.length();
367  size_t i = 0;
368  wxString prefix;
369  wxString suffix;
370  wxString tmp;
371  int braceNesting = 0;
372 
373  prefix.reserve( groupLen );
374 
375  // Parse prefix
376  //
377  for( ; i < groupLen; ++i )
378  {
379  if( aGroup[i] == '{' )
380  {
381  if( i > 0 && isSuperSub( aGroup[i-1] ) )
382  braceNesting++;
383  else
384  break;
385  }
386  else if( aGroup[i] == '}' )
387  {
388  braceNesting--;
389  }
390 
391  if( aGroup[i] == ' ' || aGroup[i] == '[' || aGroup[i] == ']' )
392  return false;
393 
394  prefix += aGroup[i];
395  }
396 
397  if( braceNesting != 0 )
398  return false;
399 
400  if( aName )
401  *aName = prefix;
402 
403  // Parse members
404  //
405  i++; // '{' character
406 
407  if( i >= groupLen )
408  return false;
409 
410  for( ; i < groupLen; ++i )
411  {
412  if( aGroup[i] == '{' )
413  {
414  if( i > 0 && isSuperSub( aGroup[i-1] ) )
415  braceNesting++;
416  else
417  return false;
418  }
419  else if( aGroup[i] == '}' )
420  {
421  if( braceNesting )
422  braceNesting--;
423  else
424  {
425  if( aMemberList )
426  aMemberList->push_back( tmp );
427 
428  return true;
429  }
430  }
431 
432  if( aGroup[i] == ' ' )
433  {
434  if( aMemberList )
435  aMemberList->push_back( tmp );
436 
437  tmp.Clear();
438  continue;
439  }
440 
441  tmp += aGroup[i];
442  }
443 
444  return false;
445 }
446 
447 
448 void NET_SETTINGS::ResolveNetClassAssignments( bool aRebuildFromScratch )
449 {
450  std::map<wxString, wxString> baseList = m_NetClassAssignments;
451 
452  if( aRebuildFromScratch )
453  {
454  for( const std::pair<const wxString, NETCLASSPTR>& netclass : m_NetClasses )
455  {
456  for( const wxString& net : *netclass.second )
457  baseList[ net ] = netclass.second->GetName();
458  }
459  }
460  else
461  {
462  baseList = m_NetClassAssignments;
463  }
464 
465  m_NetClassAssignments.clear();
466 
467  for( const auto& ii : baseList )
468  {
469  m_NetClassAssignments[ ii.first ] = ii.second;
470 
471  wxString unescaped = UnescapeString( ii.first );
472  wxString prefix;
473  std::vector<wxString> members;
474 
475  if( ParseBusVector( unescaped, &prefix, &members ) )
476  {
477  prefix = wxEmptyString;
478  }
479  else if( ParseBusGroup( unescaped, &prefix, &members ) )
480  {
481  if( !prefix.IsEmpty() )
482  prefix += wxT( "." );
483  }
484 
485  for( wxString& member : members )
486  m_NetClassAssignments[ prefix + member ] = ii.second;
487  }
488 }
std::map< wxString, wxString > m_NetClassAssignments
Definition: net_settings.h:43
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
Like a normal param, but with custom getter and setter functions.
Definition: parameters.h:296
std::map< wxString, KIGFX::COLOR4D > m_PcbNetColors
A map of fully-qualified net names to colors used in the board context.
Definition: net_settings.h:51
virtual ~NET_SETTINGS()
constexpr double PcbIu2Millimeter(int iu)
nlohmann::json json
Definition: gerbview.cpp:40
NETCLASS_MAP::const_iterator const_iterator
Definition: netclass.h:245
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:372
NESTED_SETTINGS is a JSON_SETTINGS that lives inside a JSON_SETTINGS.
constexpr int PcbMillimeter2iu(double mm)
static bool ParseBusGroup(wxString aGroup, wxString *name, std::vector< wxString > *aMemberList)
Parses a bus group label into the name and a list of components.
iterator begin()
Definition: netclass.h:242
NETCLASSES m_NetClasses
Definition: net_settings.h:39
bool isDigit(char cc)
Definition: dsnlexer.cpp:466
void ResolveNetClassAssignments(bool aRebuildFromScratch=false)
Explodes the list of netclass assignments to include atomic members of composite labels (buses).
JSON_SETTINGS * m_parent
A pointer to the parent object to load and store from.
constexpr double SchIu2Mils(int iu)
bool Add(const NETCLASSPTR &aNetclass)
Function Add takes aNetclass and puts it into this NETCLASSES container.
Definition: netclass.cpp:90
void Clear()
Function Clear destroys any contained NETCLASS instances except the Default one.
Definition: netclass.h:236
const char * name
Definition: DXF_plotter.cpp:60
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:125
static bool ParseBusVector(const wxString &aBus, wxString *aName, std::vector< wxString > *aMemberList)
Parses a bus vector (e.g.
unsigned GetCount() const
Function GetCount.
Definition: netclass.h:253
NETCLASSPTR GetDefault() const
Function GetDefault.
Definition: netclass.h:262
static bool isSuperSub(wxChar c)
constexpr int SchMils2iu(int mils)
void ReleaseNestedSettings(NESTED_SETTINGS *aSettings)
Saves and frees a nested settings object, if it exists within this one.
const int netSettingsSchemaVersion
NET_SETTINGS(JSON_SETTINGS *aParent, const std::string &aPath)
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:99