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.

368 lines
12 KiB

  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. #include <erc_item.h>
  21. #include <erc_settings.h>
  22. #include <schematic.h>
  23. #include <sch_marker.h>
  24. #include <sch_screen.h>
  25. #include <settings/parameters.h>
  26. const int ercSettingsSchemaVersion = 0;
  27. #define OK PIN_ERROR::OK
  28. #define ERR PIN_ERROR::PP_ERROR
  29. #define WAR PIN_ERROR::WARNING
  30. /**
  31. * Default Look up table which gives the ERC error level for a pair of connected pins
  32. */
  33. PIN_ERROR ERC_SETTINGS::m_defaultPinMap[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL] =
  34. {
  35. /* I, O, Bi, 3S, Pas, UnS, PwrI, PwrO, OC, OE, NC */
  36. /* I */ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
  37. /* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, ERR },
  38. /* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, ERR },
  39. /* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, ERR },
  40. /*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
  41. /*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, ERR },
  42. /*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR },
  43. /*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, ERR },
  44. /* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
  45. /* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
  46. /* NC */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }
  47. };
  48. /**
  49. * Look up table which gives the minimal drive for a pair of connected pins on
  50. * a net.
  51. * <p>
  52. * The initial state of a net is NOC (Net with No Connection). It can be updated to
  53. * NPI (Pin Isolated), NET_NC (Net with a no connect symbol), NOD (Not Driven) or DRV
  54. * (DRIven). It can be updated to NET_NC with no error only if there is only one pin
  55. * in net. Nets are OK when their final state is NET_NC or DRV. Nets with the state
  56. * NOD have no valid source signal.
  57. */
  58. int ERC_SETTINGS::m_PinMinDrive[ELECTRICAL_PINTYPES_TOTAL][ELECTRICAL_PINTYPES_TOTAL] =
  59. {
  60. /* In Out, Bi, 3S, Pas, UnS, PwrI,PwrO,OC, OE, NC */
  61. /* In*/ { NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  62. /*Out*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
  63. /* Bi*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  64. /* 3S*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  65. /*Pas*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  66. /*UnS*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  67. /*PwrI*/ { NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NPI },
  68. /*PwrO*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
  69. /* OC*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  70. /* OE*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  71. /* NC*/ { NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI }
  72. };
  73. ERC_SETTINGS::ERC_SETTINGS( JSON_SETTINGS* aParent, const std::string& aPath ) :
  74. NESTED_SETTINGS( "erc", ercSettingsSchemaVersion, aParent, aPath )
  75. {
  76. ResetPinMap();
  77. for( int i = ERCE_FIRST; i <= ERCE_LAST; ++i )
  78. m_Severities[ i ] = RPT_SEVERITY_ERROR;
  79. // Error is the default setting so set non-error priorities here.
  80. m_Severities[ERCE_UNSPECIFIED] = RPT_SEVERITY_UNDEFINED;
  81. m_Severities[ERCE_PIN_TO_PIN_WARNING] = RPT_SEVERITY_WARNING;
  82. m_Severities[ERCE_SIMILAR_LABELS] = RPT_SEVERITY_WARNING;
  83. m_Severities[ERCE_GLOBLABEL] = RPT_SEVERITY_WARNING;
  84. m_Severities[ERCE_DRIVER_CONFLICT] = RPT_SEVERITY_WARNING;
  85. m_Severities[ERCE_BUS_ENTRY_CONFLICT] = RPT_SEVERITY_WARNING;
  86. m_Severities[ERCE_LIB_SYMBOL_ISSUES] = RPT_SEVERITY_WARNING;
  87. m_Severities[ERCE_NOCONNECT_CONNECTED] = RPT_SEVERITY_WARNING;
  88. m_Severities[ERCE_NOCONNECT_NOT_CONNECTED] = RPT_SEVERITY_WARNING;
  89. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "rule_severities",
  90. [&]() -> nlohmann::json
  91. {
  92. nlohmann::json ret = {};
  93. for( const RC_ITEM& item : ERC_ITEM::GetItemsWithSeverities() )
  94. {
  95. wxString name = item.GetSettingsKey();
  96. int code = item.GetErrorCode();
  97. if( name.IsEmpty() || m_Severities.count( code ) == 0 )
  98. continue;
  99. ret[std::string( name.ToUTF8() )] = SeverityToString( m_Severities[code] );
  100. }
  101. return ret;
  102. },
  103. [&]( const nlohmann::json& aJson )
  104. {
  105. if( !aJson.is_object() )
  106. return;
  107. for( const RC_ITEM& item : ERC_ITEM::GetItemsWithSeverities() )
  108. {
  109. int code = item.GetErrorCode();
  110. wxString name = item.GetSettingsKey();
  111. std::string key( name.ToUTF8() );
  112. if( aJson.contains( key ) )
  113. m_Severities[code] = SeverityFromString( aJson[key] );
  114. }
  115. },
  116. {} ) );
  117. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "erc_exclusions",
  118. [&]() -> nlohmann::json
  119. {
  120. nlohmann::json js = nlohmann::json::array();
  121. for( const auto& entry : m_ErcExclusions )
  122. js.push_back( entry );
  123. return js;
  124. },
  125. [&]( const nlohmann::json& aObj )
  126. {
  127. m_ErcExclusions.clear();
  128. if( !aObj.is_array() )
  129. return;
  130. for( const nlohmann::json& entry : aObj )
  131. {
  132. if( entry.empty() )
  133. continue;
  134. m_ErcExclusions.insert( entry.get<wxString>() );
  135. }
  136. },
  137. {} ) );
  138. m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "pin_map",
  139. [&]() -> nlohmann::json
  140. {
  141. nlohmann::json ret = nlohmann::json::array();
  142. for( int i = 0; i < ELECTRICAL_PINTYPES_TOTAL; i++ )
  143. {
  144. nlohmann::json inner = nlohmann::json::array();
  145. for( int j = 0; j < ELECTRICAL_PINTYPES_TOTAL; j++ )
  146. inner.push_back( static_cast<int>( GetPinMapValue( i, j ) ) );
  147. ret.push_back( inner );
  148. }
  149. return ret;
  150. },
  151. [&]( const nlohmann::json& aJson )
  152. {
  153. if( !aJson.is_array() || aJson.size() != ELECTRICAL_PINTYPES_TOTAL )
  154. return;
  155. for( size_t i = 0; i < ELECTRICAL_PINTYPES_TOTAL; i++ )
  156. {
  157. if( i > aJson.size() - 1 )
  158. break;
  159. nlohmann::json inner = aJson[i];
  160. if( !inner.is_array() || inner.size() != ELECTRICAL_PINTYPES_TOTAL )
  161. return;
  162. for( size_t j = 0; j < ELECTRICAL_PINTYPES_TOTAL; j++ )
  163. {
  164. if( inner[j].is_number_integer() )
  165. {
  166. int val = inner[j].get<int>();
  167. if( val >= 0 && val <= static_cast<int>( PIN_ERROR::UNCONNECTED ) )
  168. SetPinMapValue( i, j, static_cast<PIN_ERROR>( val ) );
  169. }
  170. }
  171. }
  172. },
  173. {} ) );
  174. }
  175. ERC_SETTINGS::~ERC_SETTINGS()
  176. {
  177. if( m_parent )
  178. {
  179. m_parent->ReleaseNestedSettings( this );
  180. m_parent = nullptr;
  181. }
  182. }
  183. SEVERITY ERC_SETTINGS::GetSeverity( int aErrorCode ) const
  184. {
  185. // Special-case pin-to-pin errors:
  186. // Ignore-or-not is controlled by ERCE_PIN_TO_PIN_WARNING (for both)
  187. // Warning-or-error is controlled by which errorCode it is
  188. if( aErrorCode == ERCE_PIN_TO_PIN_ERROR )
  189. {
  190. wxASSERT( m_Severities.count( ERCE_PIN_TO_PIN_WARNING ) );
  191. if( m_Severities.at( ERCE_PIN_TO_PIN_WARNING ) == RPT_SEVERITY_IGNORE )
  192. return RPT_SEVERITY_IGNORE;
  193. else
  194. return RPT_SEVERITY_ERROR;
  195. }
  196. else if( aErrorCode == ERCE_PIN_TO_PIN_WARNING )
  197. {
  198. wxASSERT( m_Severities.count( ERCE_PIN_TO_PIN_WARNING ) );
  199. if( m_Severities.at( ERCE_PIN_TO_PIN_WARNING ) == RPT_SEVERITY_IGNORE )
  200. return RPT_SEVERITY_IGNORE;
  201. else
  202. return RPT_SEVERITY_WARNING;
  203. }
  204. wxCHECK_MSG( m_Severities.count( aErrorCode ), RPT_SEVERITY_IGNORE,
  205. "Missing severity from map in ERC_SETTINGS!" );
  206. return m_Severities.at( aErrorCode );
  207. }
  208. void ERC_SETTINGS::SetSeverity( int aErrorCode, SEVERITY aSeverity )
  209. {
  210. m_Severities[ aErrorCode ] = aSeverity;
  211. }
  212. void ERC_SETTINGS::ResetPinMap()
  213. {
  214. memcpy( m_PinMap, m_defaultPinMap, sizeof( m_PinMap ) );
  215. }
  216. void SHEETLIST_ERC_ITEMS_PROVIDER::SetSeverities( int aSeverities )
  217. {
  218. m_severities = aSeverities;
  219. m_filteredMarkers.clear();
  220. SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
  221. ERC_SETTINGS& settings = m_schematic->ErcSettings();
  222. for( unsigned i = 0; i < sheetList.size(); i++ )
  223. {
  224. for( SCH_ITEM* aItem : sheetList[i].LastScreen()->Items().OfType( SCH_MARKER_T ) )
  225. {
  226. SCH_MARKER* marker = static_cast<SCH_MARKER*>( aItem );
  227. SEVERITY markerSeverity;
  228. if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC )
  229. continue;
  230. if( marker->IsExcluded() )
  231. markerSeverity = RPT_SEVERITY_EXCLUSION;
  232. else
  233. markerSeverity = settings.GetSeverity( marker->GetRCItem()->GetErrorCode() );
  234. if( markerSeverity & m_severities )
  235. m_filteredMarkers.push_back( marker );
  236. }
  237. }
  238. }
  239. int SHEETLIST_ERC_ITEMS_PROVIDER::GetCount( int aSeverity )
  240. {
  241. if( aSeverity < 0 )
  242. return m_filteredMarkers.size();
  243. int count = 0;
  244. SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
  245. ERC_SETTINGS& settings = m_schematic->ErcSettings();
  246. for( unsigned i = 0; i < sheetList.size(); i++ )
  247. {
  248. for( SCH_ITEM* aItem : sheetList[i].LastScreen()->Items().OfType( SCH_MARKER_T ) )
  249. {
  250. SCH_MARKER* marker = static_cast<SCH_MARKER*>( aItem );
  251. SEVERITY markerSeverity;
  252. if( marker->GetMarkerType() != MARKER_BASE::MARKER_ERC )
  253. continue;
  254. if( marker->IsExcluded() )
  255. markerSeverity = RPT_SEVERITY_EXCLUSION;
  256. else
  257. markerSeverity = settings.GetSeverity( marker->GetRCItem()->GetErrorCode() );
  258. if( markerSeverity == aSeverity )
  259. count++;
  260. }
  261. }
  262. return count;
  263. }
  264. std::shared_ptr<ERC_ITEM> SHEETLIST_ERC_ITEMS_PROVIDER::GetERCItem( int aIndex )
  265. {
  266. SCH_MARKER* marker = m_filteredMarkers[ aIndex ];
  267. return marker ? std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() ) : nullptr;
  268. }
  269. std::shared_ptr<RC_ITEM> SHEETLIST_ERC_ITEMS_PROVIDER::GetItem( int aIndex )
  270. {
  271. return GetERCItem( aIndex );
  272. }
  273. void SHEETLIST_ERC_ITEMS_PROVIDER::DeleteItem( int aIndex, bool aDeep )
  274. {
  275. SCH_MARKER* marker = m_filteredMarkers[ aIndex ];
  276. m_filteredMarkers.erase( m_filteredMarkers.begin() + aIndex );
  277. if( aDeep )
  278. {
  279. SCH_SCREENS screens( m_schematic->Root() );
  280. screens.DeleteMarker( marker );
  281. }
  282. }
  283. void SHEETLIST_ERC_ITEMS_PROVIDER::DeleteAllItems( bool aIncludeExclusions, bool aDeep )
  284. {
  285. // Filtered list was already handled through DeleteItem() by the tree control
  286. if( aDeep )
  287. {
  288. SCH_SCREENS screens( m_schematic->Root() );
  289. screens.DeleteAllMarkers( MARKER_BASE::MARKER_ERC, aIncludeExclusions );
  290. }
  291. }