/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2016 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 gbr_metadata.cpp * @brief helper functions to handle the gerber metadata in files, * related to the netlist info and aperture attribute. */ #include #include std::string GBR_APERTURE_METADATA::FormatAttribute( GBR_APERTURE_ATTRIB aAttribute ) { std::string attribute_string; // generate a string to print a Gerber Aperture attribute switch( aAttribute ) { case GBR_APERTURE_ATTRIB_END: // Dummy value (aAttribute must be < GBR_APERTURE_ATTRIB_END) case GBR_APERTURE_ATTRIB_NONE: // idle command: do nothing break; case GBR_APERTURE_ATTRIB_ETCHEDCMP: // print info associated to an item // which connects 2 different nets // (Net tees, microwave component) attribute_string = "%TA.AperFunction,EtchedComponent*%\n"; break; case GBR_APERTURE_ATTRIB_CONDUCTOR: // print info associated to a track attribute_string = "%TA.AperFunction,Conductor*%\n"; break; case GBR_APERTURE_ATTRIB_CUTOUT: // print info associated to a outline attribute_string = "%TA.AperFunction,CutOut*%\n"; break; case GBR_APERTURE_ATTRIB_VIAPAD: // print info associated to a flashed via attribute_string = "%TA.AperFunction,ViaPad*%\n"; break; case GBR_APERTURE_ATTRIB_NONCONDUCTOR: // print info associated to a item on a copper layer // which is not a track (for instance a text) attribute_string = "%TA.AperFunction,NonConductor*%\n"; break; case GBR_APERTURE_ATTRIB_COMPONENTPAD: // print info associated to a flashed // through hole component on outer layer attribute_string = "%TA.AperFunction,ComponentPad*%\n"; break; case GBR_APERTURE_ATTRIB_SMDPAD_SMDEF: // print info associated to a flashed for SMD pad. // with solder mask defined from the copper shape // Excluded BGA pads which have their own type attribute_string = "%TA.AperFunction,SMDPad,SMDef*%\n"; break; case GBR_APERTURE_ATTRIB_SMDPAD_CUDEF: // print info associated to a flashed SMD pad with // a solder mask defined by the solder mask attribute_string = "%TA.AperFunction,SMDPad,CuDef*%\n"; break; case GBR_APERTURE_ATTRIB_BGAPAD_SMDEF: // print info associated to flashed BGA pads with // a solder mask defined by the copper shape attribute_string = "%TA.AperFunction,BGAPad,SMDef*%\n"; break; case GBR_APERTURE_ATTRIB_BGAPAD_CUDEF: // print info associated to a flashed BGA pad with // a solder mask defined by the solder mask attribute_string = "%TA.AperFunction,BGAPad,CuDef*%\n"; break; case GBR_APERTURE_ATTRIB_CONNECTORPAD: // print info associated to a flashed edge connector pad (outer layers) attribute_string = "%TA.AperFunction,ConnectorPad*%\n"; break; case GBR_APERTURE_ATTRIB_WASHERPAD: // print info associated to flashed mechanical pads (NPTH) attribute_string = "%TA.AperFunction,WasherPad*%\n"; break; case GBR_APERTURE_ATTRIB_HEATSINKPAD: // print info associated to a flashed heat sink pad // (typically for SMDs) attribute_string = "%TA.AperFunction,HeatsinkPad*%\n"; break; case GBR_APERTURE_ATTRIB_VIADRILL: // print info associated to a via hole in drill files attribute_string = "%TA.AperFunction,ViaDrill*%\n"; break; case GBR_APERTURE_ATTRIB_COMPONENTDRILL: // print info associated to a component // round hole in drill files attribute_string = "%TA.AperFunction,ComponentDrill*%\n"; break; case GBR_APERTURE_ATTRIB_SLOTDRILL: // print info associated to a oblong hole in drill files attribute_string = "%TA.AperFunction,Slot*%\n"; break; } return attribute_string; } wxString FormatStringFromGerber( const wxString& aString ) { // make the inverse conversion of formatStringToGerber() // It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode // and return a wxString (unicode 16) from the gerber string wxString txt; for( unsigned ii = 0; ii < aString.Length(); ++ii ) { unsigned code = aString[ii]; if( code == '\\' ) { // Convert 4 hexadecimal digits to a 16 bit unicode // (Gerber allows only 4 hexadecimal digits) long value = 0; for( int jj = 0; jj < 4; jj++ ) { value <<= 4; code = aString[++ii]; // Very basic conversion, but it expects a valid gerber file int hexa = (code <= '9' ? code - '0' : code - 'A' + 10) & 0xF; value += hexa; } txt.Append( wxChar( value ) ); } else txt.Append( aString[ii] ); } return txt; } std::string formatStringToGerber( const wxString& aString ) { /* format string means convert any code > 0x7F and unautorized code to a hexadecimal * 16 bits sequence unicode * unautorized codes are ',' '*' '%' '\' */ std::string txt; txt.reserve( aString.Length() ); for( unsigned ii = 0; ii < aString.Length(); ++ii ) { unsigned code = aString[ii]; bool convert = false; switch( code ) { case '\\': case '%': case '*': case ',': convert = true; break; default: break; } if( convert || code > 0x7F ) { txt += '\\'; // Convert code to 4 hexadecimal digit // (Gerber allows only 4 hexadecimal digit) char hexa[32]; sprintf( hexa,"%4.4X", code & 0xFFFF); txt += hexa; } else txt += char( code ); } return txt; } // Netname and Pan num fields cannot be empty in Gerber files // Normalized names must be used, if any #define NO_NET_NAME wxT( "N/C" ) // net name of not connected pads (one pad net) (normalized) #define NO_PAD_NAME wxT( "" ) // pad name of pads without pad name/number (not normalized) bool FormatNetAttribute( std::string& aPrintedText, std::string& aLastNetAttributes, GBR_NETLIST_METADATA* aData, bool& aClearPreviousAttributes ) { aClearPreviousAttributes = false; // print a Gerber net attribute record. // it is added to the object attributes dictionnary // On file, only modified or new attributes are printed. if( aData == NULL ) return false; std::string pad_attribute_string; std::string net_attribute_string; std::string cmp_attribute_string; if( aData->m_NetAttribType == GBR_NETLIST_METADATA::GBR_NETINFO_UNSPECIFIED ) return false; // idle command: do nothing if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) ) { // print info associated to a flashed pad (cmpref, pad name) // example: %TO.P,R5,3*% pad_attribute_string = "%TO.P,"; pad_attribute_string += formatStringToGerber( aData->m_Cmpref ) + ","; if( aData->m_Padname.IsEmpty() ) // Happens for "mechanical" or never connected pads pad_attribute_string += formatStringToGerber( NO_PAD_NAME ); else pad_attribute_string += formatStringToGerber( aData->m_Padname ); pad_attribute_string += "*%\n"; } if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_NET ) ) { // print info associated to a net // example: %TO.N,Clk3*% net_attribute_string = "%TO.N,"; if( aData->m_Netname.IsEmpty() ) { if( aData->m_NotInNet ) { // Happens for not connectable pads: mechanical pads // and pads with no padname/num // In this case the net name must be left empty } else { // Happens for not connected pads: use a normalized // dummy name net_attribute_string += formatStringToGerber( NO_NET_NAME ); } } else net_attribute_string += formatStringToGerber( aData->m_Netname ); net_attribute_string += "*%\n"; } if( ( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_CMP ) && !( aData->m_NetAttribType & GBR_NETLIST_METADATA::GBR_NETINFO_PAD ) ) { // print info associated to a footprint // example: %TO.C,R2*% // Because GBR_NETINFO_PAD option already contains this info, it is not // created here for a GBR_NETINFO_PAD attribute cmp_attribute_string = "%TO.C,"; cmp_attribute_string += formatStringToGerber( aData->m_Cmpref ) + "*%\n"; } // the full list of requested attributes: std::string full_attribute_string = pad_attribute_string + net_attribute_string + cmp_attribute_string; // the short list of requested attributes // (only modified or new attributes are stored here): std::string short_attribute_string; if( aLastNetAttributes != full_attribute_string ) { // first, remove no more existing attributes. // Because in Kicad the full attribute list is evaluated for each object, // the entire dictionnary is cleared bool clearDict = false; if( aLastNetAttributes.find( "%TO.P," ) != std::string::npos ) { if( pad_attribute_string.empty() ) // No more this attribute clearDict = true; else if( aLastNetAttributes.find( pad_attribute_string ) == std::string::npos ) // This attribute has changed short_attribute_string += pad_attribute_string; } else // New attribute short_attribute_string += pad_attribute_string; if( aLastNetAttributes.find( "%TO.N," ) != std::string::npos ) { if( net_attribute_string.empty() ) // No more this attribute clearDict = true; else if( aLastNetAttributes.find( net_attribute_string ) == std::string::npos ) // This attribute has changed short_attribute_string += net_attribute_string; } else // New attribute short_attribute_string += net_attribute_string; if( aLastNetAttributes.find( "%TO.C," ) != std::string::npos ) { if( cmp_attribute_string.empty() ) // No more this attribute clearDict = true; else if( aLastNetAttributes.find( cmp_attribute_string ) == std::string::npos ) // This attribute has changed short_attribute_string += cmp_attribute_string; } else // New attribute short_attribute_string += cmp_attribute_string; aClearPreviousAttributes = clearDict; aLastNetAttributes = full_attribute_string; if( clearDict ) aPrintedText = full_attribute_string; else aPrintedText = short_attribute_string; } return true; }