/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 1992-2011 jean-pierre Charras * Copyright (C) 1992-2011 Wayne Stambaugh * Copyright (C) 1992-2018 KiCad Developers, see authors.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** * @file eeschema/sch_reference_list.h */ #ifndef _SCH_REFERENCE_LIST_H_ #define _SCH_REFERENCE_LIST_H_ #include #include #include #include #include #include class SCH_REFERENCE; class SCH_REFERENCE_LIST; /** * SCH_REFERENCE * is used as a helper to define a component's reference designator in a schematic. This * helper is required in a complex hierarchy because a component can be used more than * once and its reference depends on the sheet path. This class is used to flatten the * schematic hierarchy for annotation, net list generation, and bill of material * generation. */ class SCH_REFERENCE { /// Component reference prefix, without number (for IC1, this is IC) ) UTF8 m_Ref; // it's private, use the accessors please SCH_COMPONENT* m_RootCmp; ///< The component associated the reference object. LIB_PART* m_Entry; ///< The source component from a library. wxPoint m_CmpPos; ///< The physical position of the component in schematic ///< used to annotate by X or Y position int m_Unit; ///< The unit number for components with multiple parts ///< per package. SCH_SHEET_PATH m_SheetPath; ///< The sheet path for this reference. bool m_IsNew; ///< True if not yet annotated. int m_SheetNum; ///< The sheet number for the reference. timestamp_t m_TimeStamp; ///< The time stamp for the reference. EDA_TEXT* m_Value; ///< The component value of the reference. It is the ///< same for all instances. int m_NumRef; ///< The numeric part of the reference designator. int m_Flag; friend class SCH_REFERENCE_LIST; public: SCH_REFERENCE() : m_SheetPath() { m_RootCmp = NULL; m_Entry = NULL; m_Unit = 0; m_TimeStamp = 0; m_IsNew = false; m_Value = NULL; m_NumRef = 0; m_Flag = 0; m_SheetNum = 0; } SCH_REFERENCE( SCH_COMPONENT* aComponent, LIB_PART* aLibComponent, SCH_SHEET_PATH& aSheetPath ); SCH_COMPONENT* GetComp() const { return m_RootCmp; } LIB_PART* GetLibPart() const { return m_Entry; } const SCH_SHEET_PATH& GetSheetPath() const { return m_SheetPath; } SCH_SHEET_PATH& GetSheetPath() { return m_SheetPath; } int GetUnit() const { return m_Unit; } void SetSheetNumber( int aSheetNumber ) { m_SheetNum = aSheetNumber; } const wxString GetPath() const { return m_RootCmp ? m_RootCmp->GetPath( &m_SheetPath ) : ""; } /** * Function Annotate * updates the annotation of the component according the the current object state. */ void Annotate(); /** * Function Split * attempts to split the reference designator into a name (U) and number (1). If the * last character is '?' or not a digit, the reference is tagged as not annotated. * For components with multiple parts per package that are not already annotated, set * m_Unit to a max value (0x7FFFFFFF). */ void Split(); /* Some accessors which hide the strategy of how the reference is stored, thereby making it easy to change that strategy. */ void SetRef( const wxString& aReference ) { m_Ref = aReference; } wxString GetRef() const { return m_Ref; } void SetRefStr( const std::string& aReference ) { m_Ref = aReference; } const char* GetRefStr() const { return m_Ref.c_str(); } ///> Return reference name with unit altogether wxString GetFullRef() { if( GetComp()->GetUnitCount() > 1 ) return GetRef() + LIB_PART::SubReference( GetUnit() ); else return GetRef(); } wxString GetRefNumber() const { wxString ref; if( m_NumRef < 0 ) return wxT( "?" ); // To avoid a risk of duplicate, for power components // the ref number is 0nnn instead of nnn. // Just because sometimes only power components are annotated if( GetLibPart() && GetLibPart()->IsPower() ) ref = wxT( "0" ); return ref << m_NumRef; } int CompareValue( const SCH_REFERENCE& item ) const { return m_Value->GetText().Cmp( item.m_Value->GetText() ); } int CompareRef( const SCH_REFERENCE& item ) const { return m_Ref.compare( item.m_Ref ); } int CompareLibName( const SCH_REFERENCE& item ) const { return m_RootCmp->GetLibId().GetLibItemName().compare( item.m_RootCmp->GetLibId().GetLibItemName() ); } /** * Function IsSameInstance * returns whether this reference refers to the same component instance * (component and sheet) as another. */ bool IsSameInstance( const SCH_REFERENCE& other ) const { return GetComp() == other.GetComp() && GetSheetPath().Path() == other.GetSheetPath().Path(); } bool IsUnitsLocked() { return m_Entry->UnitsLocked(); } }; /** * SCH_REFERENCE_LIST * is used to create a flattened list of components because in a complex hierarchy, a component * can be used more than once and its reference designator is dependent on the sheet path for * the same component. This flattened list is used for netlist generation, BOM generation, * and schematic annotation. */ class SCH_REFERENCE_LIST { private: std::vector componentFlatList; public: /** Constructor */ SCH_REFERENCE_LIST() { } SCH_REFERENCE& operator[]( int aIndex ) { return componentFlatList[ aIndex ]; } /** * Function GetCount * @return the number of items in the list */ unsigned GetCount() { return componentFlatList.size(); } /** * Function GetItem * @return the aIdx item */ SCH_REFERENCE& GetItem( int aIdx ) { return componentFlatList[aIdx]; } /** * Function AddItem * adds a SCH_REFERENCE object to the list of references. * @param aItem - a SCH_REFERENCE item to add */ void AddItem( SCH_REFERENCE& aItem ) { componentFlatList.push_back( aItem ); } /** * Function RemoveItem * removes an item from the list of references. * * @param aIndex is the index of the item to be removed. */ void RemoveItem( unsigned int aIndex ); /** * Function RemoveSubComponentsFromList * Remove sub components from the list, when multiples parts per package are * found in this list. * Useful to create BOM, when a component must appear only once */ void RemoveSubComponentsFromList(); /* Sort functions: * Sort functions are used to sort components for annotation or BOM generation. * Because sorting depends on what we want to do, there are many sort functions. * Note: * When creating BOM, components are fully annotated. * references are something like U3, U5 or R4, R8 * When annotating, some or all components are not annotated, * i.e. ref is only U or R, with no number. */ /** * Function SplitReferences * attempts to split all reference designators into a name (U) and number (1). If the * last character is '?' or not a digit, the reference is tagged as not annotated. * For components with multiple parts per package that are not already annotated, set * m_Unit to a max value (0x7FFFFFFF). * @see SCH_REFERENCE::Split() */ void SplitReferences() { for( unsigned ii = 0; ii < GetCount(); ii++ ) componentFlatList[ii].Split(); } /** * function UpdateAnnotation * Updates the reference components for the schematic project (or the current sheet) * Note: this function does not calculate the reference numbers stored in m_NumRef * So, it must be called after calculation of new reference numbers * @see SCH_REFERENCE::Annotate() */ void UpdateAnnotation() { /* update the reference numbers */ for( unsigned ii = 0; ii < GetCount(); ii++ ) { componentFlatList[ii].Annotate(); } } /** * Function Annotate * set the reference designators in the list that have not been annotated. * @param aUseSheetNum Set to true to start annotation for each sheet at the sheet number * times \a aSheetIntervalId. Otherwise annotate incrementally. * @param aSheetIntervalId The per sheet reference designator multiplier. * @param aStartNumber The number to start with if NOT numbering based on sheet number. * @param aLockedUnitMap A SCH_MULTI_UNIT_REFERENCE_MAP of reference designator wxStrings * to SCH_REFERENCE_LISTs. May be an empty map. If not empty, any multi-unit parts * found in this map will be annotated as a group rather than individually. *

* If a the sheet number is 2 and \a aSheetIntervalId is 100, then the first reference * designator would be 201 and the last reference designator would be 299 when no overlap * occurs with sheet number 3. If there are 150 items in sheet number 2, then items are * referenced U201 to U351, and items in sheet 3 start from U352 *

*/ void Annotate( bool aUseSheetNum, int aSheetIntervalId, int aStartNumber, SCH_MULTI_UNIT_REFERENCE_MAP aLockedUnitMap ); /** * Function CheckAnnotation * check for annotations errors. *

* The following annotation error conditions are tested: *

    *
  • Components not annotated.
  • *
  • Components having the same reference designator (duplicates).
  • *
  • Components with multiple parts per package having different reference designators.
  • *
  • Components with multiple parts per package with invalid part count.
  • *
*

* @param aReporter A sink for error messages. Use NULL_REPORTER if you don't need errors. * @return The number of errors found. */ int CheckAnnotation( REPORTER& aReporter ); /** * @brief Check components having same references designator. Must be called with references * sorted by timestamp \ref SortByTimeStamp() * @param aReporter A sink for error messages. Use NULL_REPORTER if you don't need errors. * @return The number of errors found. */ int checkForDuplicatedElements( REPORTER& aReporter ); /** * Function sortByXCoordinate * sorts the list of references by X position. *

* Components are sorted as follows: *

    *
  • Numeric value of reference designator.
  • *
  • Sheet number.
  • *
  • X coordinate position.
  • *
  • Y coordinate position.
  • *
  • Time stamp.
  • *
*

*/ void SortByXCoordinate() { sort( componentFlatList.begin(), componentFlatList.end(), sortByXPosition ); } /** * Function sortByYCoordinate * sorts the list of references by Y position. *

* Components are sorted as follows: *

    *
  • Numeric value of reference designator.
  • *
  • Sheet number.
  • *
  • Y coordinate position.
  • *
  • X coordinate position.
  • *
  • Time stamp.
  • *
*

*/ void SortByYCoordinate() { sort( componentFlatList.begin(), componentFlatList.end(), sortByYPosition ); } /** * Function SortComponentsByTimeStamp * sort the flat list by Time Stamp (sheet path + timestamp). * Useful to detect duplicate Time Stamps */ void SortByTimeStamp() { sort( componentFlatList.begin(), componentFlatList.end(), sortByTimeStamp ); } /** * Function SortByRefAndValue * sorts the list of references by value. *

* Components are sorted in the following order: *

    *
  • Numeric value of reference designator.
  • *
  • Value of component.
  • *
  • Unit number when component has multiple parts.
  • *
  • Sheet number.
  • *
  • X coordinate position.
  • *
  • Y coordinate position.
  • *
*

*/ void SortByRefAndValue() { sort( componentFlatList.begin(), componentFlatList.end(), sortByRefAndValue ); } /** * Function SortByReferenceOnly * sorts the list of references by reference. *

* Components are sorted in the following order: *

    *
  • Numeric value of reference designator.
  • *
  • Unit number when component has multiple parts.
  • *
*

*/ void SortByReferenceOnly() { sort( componentFlatList.begin(), componentFlatList.end(), sortByReferenceOnly ); } /** * searches the sorted list of components for a another component with the same * reference and a given part unit. Use this method to manage components with * multiple parts per package. * @param aIndex = index in aComponentsList for of given SCH_REFERENCE item to test. * @param aUnit = the given unit number to search * @return index in aComponentsList if found or -1 if not found */ int FindUnit( size_t aIndex, int aUnit ); /** * @brief Searches unit with designated path * @param aPath path to search * @return index in aComponentsList if found or -1 if not found */ int FindRefByPath( const wxString& aPath ) const; /** * Function GetRefsInUse * adds all the reference designator numbers greater than \a aMinRefId to \a aIdList * skipping the reference at \a aIndex. * @param aIndex = the current component index to use for reference prefix filtering. * @param aIdList = the buffer to fill * @param aMinRefId = the min id value to store. all values < aMinRefId are ignored */ void GetRefsInUse( int aIndex, std::vector< int >& aIdList, int aMinRefId ); /** * Function GetLastReference * returns the last used (greatest) reference number in the reference list * for the prefix reference given by \a aIndex. The component list must be * sorted. * * @param aIndex The index of the reference item used for the search pattern. * @param aMinValue The minimum value for the current search. */ int GetLastReference( int aIndex, int aMinValue ); #if defined(DEBUG) void Show( const char* aPrefix = "" ) { printf( "%s\n", aPrefix ); for( unsigned i=0; iGetName() ) ); } } #endif /** * Function Shorthand * Returns a shorthand string representing all the references in the list. For instance, * "R1, R2, R4 - R7, U1" * @param aList */ static wxString Shorthand( std::vector aList ); friend class BACK_ANNOTATION; private: /* sort functions used to sort componentFlatList */ static bool sortByRefAndValue( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByXPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByYPosition( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByTimeStamp( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); static bool sortByReferenceOnly( const SCH_REFERENCE& item1, const SCH_REFERENCE& item2 ); /** * Function CreateFirstFreeRefId * searches for the first free reference number in \a aListId of reference numbers in use. * This function just searches for a hole in a list of incremented numbers, this list must * be sorted by increasing values and each value can be stored only once. The new value * is added to the list. * @see BuildRefIdInUseList to prepare this list * @param aIdList The buffer that contains the reference numbers in use. * @param aFirstValue The first expected free value * @return The first free (not yet used) value. */ int CreateFirstFreeRefId( std::vector& aIdList, int aFirstValue ); // Used for sorting static sortByTimeStamp function friend class BACK_ANNOTATE; }; #endif // _SCH_REFERENCE_LIST_H_