You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
11 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <bus_alias.h>
  20. #include <connection_graph.h>
  21. #include <erc_settings.h>
  22. #include <sch_marker.h>
  23. #include <project.h>
  24. #include <project/project_file.h>
  25. #include <project/net_settings.h>
  26. #include <schematic.h>
  27. #include <sch_screen.h>
  28. #include <sim/spice_settings.h>
  29. SCHEMATIC::SCHEMATIC( PROJECT* aPrj ) :
  30. EDA_ITEM( nullptr, SCHEMATIC_T ),
  31. m_project( nullptr ),
  32. m_rootSheet( nullptr )
  33. {
  34. m_currentSheet = new SCH_SHEET_PATH();
  35. m_connectionGraph = new CONNECTION_GRAPH( this );
  36. SetProject( aPrj );
  37. }
  38. SCHEMATIC::~SCHEMATIC()
  39. {
  40. delete m_currentSheet;
  41. delete m_connectionGraph;
  42. }
  43. void SCHEMATIC::Reset()
  44. {
  45. // Assume project already saved
  46. if( m_project )
  47. {
  48. PROJECT_FILE& project = m_project->GetProjectFile();
  49. delete project.m_ErcSettings;
  50. delete project.m_SchematicSettings;
  51. project.m_ErcSettings = nullptr;
  52. project.m_SchematicSettings = nullptr;
  53. m_project = nullptr; // clear the project, so we don't do this again when setting a new one
  54. }
  55. delete m_rootSheet;
  56. m_rootSheet = nullptr;
  57. m_connectionGraph->Reset();
  58. m_currentSheet->clear();
  59. }
  60. void SCHEMATIC::SetProject( PROJECT* aPrj )
  61. {
  62. if( m_project )
  63. {
  64. PROJECT_FILE& project = m_project->GetProjectFile();
  65. delete project.m_ErcSettings;
  66. delete project.m_SchematicSettings;
  67. project.m_ErcSettings = nullptr;
  68. project.m_SchematicSettings = nullptr;
  69. }
  70. m_project = aPrj;
  71. if( m_project )
  72. {
  73. PROJECT_FILE& project = m_project->GetProjectFile();
  74. project.m_ErcSettings = new ERC_SETTINGS( &project, "erc" );
  75. project.m_SchematicSettings = new SCHEMATIC_SETTINGS( &project, "schematic" );
  76. project.m_SchematicSettings->LoadFromFile();
  77. project.m_SchematicSettings->m_NgspiceSimulatorSettings->LoadFromFile();
  78. project.m_ErcSettings->LoadFromFile();
  79. }
  80. }
  81. void SCHEMATIC::SetRoot( SCH_SHEET* aRootSheet )
  82. {
  83. wxCHECK_RET( aRootSheet, wxT( "Call to SetRoot with null SCH_SHEET!" ) );
  84. m_rootSheet = aRootSheet;
  85. m_currentSheet->clear();
  86. m_currentSheet->push_back( m_rootSheet );
  87. m_connectionGraph->Reset();
  88. }
  89. SCH_SCREEN* SCHEMATIC::RootScreen() const
  90. {
  91. return IsValid() ? m_rootSheet->GetScreen() : nullptr;
  92. }
  93. bool SCHEMATIC::ResolveTextVar( wxString* token, int aDepth ) const
  94. {
  95. if( !CurrentSheet().empty() )
  96. {
  97. if( token->IsSameAs( wxT( "#" ) ) )
  98. {
  99. *token = CurrentSheet().GetPageNumber();
  100. return true;
  101. }
  102. else if( token->IsSameAs( wxT( "##" ) ) )
  103. {
  104. *token = wxString::Format( wxT( "%i" ), Root().CountSheets() );
  105. return true;
  106. }
  107. else if( token->IsSameAs( wxT( "SHEETNAME" ) ) )
  108. {
  109. *token = CurrentSheet().PathHumanReadable();
  110. return true;
  111. }
  112. else if( token->IsSameAs( wxT( "FILENAME" ) ) )
  113. {
  114. wxFileName fn( GetFileName() );
  115. *token = fn.GetFullName();
  116. return true;
  117. }
  118. else if( token->IsSameAs( wxT( "PROJECTNAME" ) ) )
  119. {
  120. *token = Prj().GetProjectName();
  121. return true;
  122. }
  123. return CurrentSheet().LastScreen()->GetTitleBlock().TextVarResolver( token, m_project );
  124. }
  125. return false;
  126. }
  127. wxString SCHEMATIC::GetFileName() const
  128. {
  129. return IsValid() ? m_rootSheet->GetScreen()->GetFileName() : wxString( wxEmptyString );
  130. }
  131. SCHEMATIC_SETTINGS& SCHEMATIC::Settings() const
  132. {
  133. wxASSERT( m_project );
  134. return *m_project->GetProjectFile().m_SchematicSettings;
  135. }
  136. ERC_SETTINGS& SCHEMATIC::ErcSettings() const
  137. {
  138. wxASSERT( m_project );
  139. return *m_project->GetProjectFile().m_ErcSettings;
  140. }
  141. std::vector<SCH_MARKER*> SCHEMATIC::ResolveERCExclusions()
  142. {
  143. SCH_SHEET_LIST sheetList = GetSheets();
  144. ERC_SETTINGS& settings = ErcSettings();
  145. for( const SCH_SHEET_PATH& sheet : sheetList )
  146. {
  147. for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_MARKER_T ) )
  148. {
  149. SCH_MARKER* marker = static_cast<SCH_MARKER*>( item );
  150. auto it = settings.m_ErcExclusions.find( marker->Serialize() );
  151. if( it != settings.m_ErcExclusions.end() )
  152. {
  153. marker->SetExcluded( true );
  154. settings.m_ErcExclusions.erase( it );
  155. }
  156. }
  157. }
  158. std::vector<SCH_MARKER*> newMarkers;
  159. for( const wxString& exclusionData : settings.m_ErcExclusions )
  160. {
  161. SCH_MARKER* marker = SCH_MARKER::Deserialize( exclusionData );
  162. if( marker )
  163. {
  164. marker->SetExcluded( true );
  165. newMarkers.push_back( marker );
  166. }
  167. }
  168. settings.m_ErcExclusions.clear();
  169. return newMarkers;
  170. }
  171. std::shared_ptr<BUS_ALIAS> SCHEMATIC::GetBusAlias( const wxString& aLabel ) const
  172. {
  173. for( const auto& sheet : GetSheets() )
  174. {
  175. for( const auto& alias : sheet.LastScreen()->GetBusAliases() )
  176. {
  177. if( alias->GetName() == aLabel )
  178. return alias;
  179. }
  180. }
  181. return nullptr;
  182. }
  183. std::vector<wxString> SCHEMATIC::GetNetClassAssignmentCandidates()
  184. {
  185. std::vector<wxString> names;
  186. // Key is a NET_NAME_CODE aka std::pair<name, code>
  187. for( const NET_MAP::value_type& pair: m_connectionGraph->GetNetMap() )
  188. {
  189. CONNECTION_SUBGRAPH* subgraph = pair.second[0];
  190. if( !subgraph->m_driver_connection->IsBus()
  191. && subgraph->GetDriverPriority() >= CONNECTION_SUBGRAPH::PRIORITY::PIN )
  192. {
  193. names.emplace_back( pair.first.first );
  194. }
  195. }
  196. return names;
  197. }
  198. bool SCHEMATIC::ResolveCrossReference( wxString* token, int aDepth ) const
  199. {
  200. SCH_SHEET_LIST sheetList = GetSheets();
  201. wxString remainder;
  202. wxString ref = token->BeforeFirst( ':', &remainder );
  203. SCH_SHEET_PATH sheetPath;
  204. SCH_ITEM* refItem = sheetList.GetItem( KIID( ref ), &sheetPath );
  205. if( refItem && refItem->Type() == SCH_SYMBOL_T )
  206. {
  207. SCH_SYMBOL* refSymbol = static_cast<SCH_SYMBOL*>( refItem );
  208. if( refSymbol->ResolveTextVar( &remainder, aDepth + 1 ) )
  209. *token = remainder;
  210. else
  211. *token = refSymbol->GetRef( &sheetPath, true ) + wxT( ":" ) + remainder;
  212. return true; // Cross-reference is resolved whether or not the actual textvar was
  213. }
  214. else if( refItem && refItem->Type() == SCH_SHEET_T )
  215. {
  216. SCH_SHEET* refSheet = static_cast<SCH_SHEET*>( refItem );
  217. if( refSheet->ResolveTextVar( &remainder, aDepth + 1 ) )
  218. *token = remainder;
  219. return true; // Cross-reference is resolved whether or not the actual textvar was
  220. }
  221. return false;
  222. }
  223. wxString SCHEMATIC::ConvertRefsToKIIDs( const wxString& aSource ) const
  224. {
  225. wxString newbuf;
  226. size_t sourceLen = aSource.length();
  227. for( size_t i = 0; i < sourceLen; ++i )
  228. {
  229. if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
  230. {
  231. wxString token;
  232. bool isCrossRef = false;
  233. for( i = i + 2; i < sourceLen; ++i )
  234. {
  235. if( aSource[i] == '}' )
  236. break;
  237. if( aSource[i] == ':' )
  238. isCrossRef = true;
  239. token.append( aSource[i] );
  240. }
  241. if( isCrossRef )
  242. {
  243. SCH_SHEET_LIST sheetList = GetSheets();
  244. wxString remainder;
  245. wxString ref = token.BeforeFirst( ':', &remainder );
  246. SCH_REFERENCE_LIST references;
  247. sheetList.GetSymbols( references );
  248. for( size_t jj = 0; jj < references.GetCount(); jj++ )
  249. {
  250. SCH_SYMBOL* refSymbol = references[ jj ].GetSymbol();
  251. if( ref == refSymbol->GetRef( &references[ jj ].GetSheetPath(), true ) )
  252. {
  253. token = refSymbol->m_Uuid.AsString() + wxT( ":" ) + remainder;
  254. break;
  255. }
  256. }
  257. }
  258. newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
  259. }
  260. else
  261. {
  262. newbuf.append( aSource[i] );
  263. }
  264. }
  265. return newbuf;
  266. }
  267. wxString SCHEMATIC::ConvertKIIDsToRefs( const wxString& aSource ) const
  268. {
  269. wxString newbuf;
  270. size_t sourceLen = aSource.length();
  271. for( size_t i = 0; i < sourceLen; ++i )
  272. {
  273. if( aSource[i] == '$' && i + 1 < sourceLen && aSource[i+1] == '{' )
  274. {
  275. wxString token;
  276. bool isCrossRef = false;
  277. for( i = i + 2; i < sourceLen; ++i )
  278. {
  279. if( aSource[i] == '}' )
  280. break;
  281. if( aSource[i] == ':' )
  282. isCrossRef = true;
  283. token.append( aSource[i] );
  284. }
  285. if( isCrossRef )
  286. {
  287. SCH_SHEET_LIST sheetList = GetSheets();
  288. wxString remainder;
  289. wxString ref = token.BeforeFirst( ':', &remainder );
  290. SCH_SHEET_PATH refSheetPath;
  291. SCH_ITEM* refItem = sheetList.GetItem( KIID( ref ), &refSheetPath );
  292. if( refItem && refItem->Type() == SCH_SYMBOL_T )
  293. {
  294. SCH_SYMBOL* refSymbol = static_cast<SCH_SYMBOL*>( refItem );
  295. token = refSymbol->GetRef( &refSheetPath, true ) + wxT( ":" ) + remainder;
  296. }
  297. }
  298. newbuf.append( wxT( "${" ) + token + wxT( "}" ) );
  299. }
  300. else
  301. {
  302. newbuf.append( aSource[i] );
  303. }
  304. }
  305. return newbuf;
  306. }
  307. SCH_SHEET_LIST& SCHEMATIC::GetFullHierarchy() const
  308. {
  309. static SCH_SHEET_LIST hierarchy;
  310. hierarchy.clear();
  311. hierarchy.BuildSheetList( m_rootSheet, false );
  312. return hierarchy;
  313. }