Commit 709be495 authored by dickelbeck's avatar dickelbeck

more amazing free specctra work

parent 10ded82d
......@@ -5,6 +5,15 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with
email address.
2008-Feb-13 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
+pcbnew
specctra export: now generate unique pin names from module padnames in the
case where there are non-unique pad names within a module. Tested with
Electra demo, and *.dsn files load OK in there as well as in freerouter.
Stopped using reserved layer name "signal" and instead output a full
padstack consisting of all pertinent layers for via, pads, and keepouts.
2008-Feb-12 UPDATE Tim Hanson sideskate@gmail.com
================================================================================
......@@ -18,7 +27,7 @@ email address.
** GetScreen is virtual, as some of the dialogs keep around a WinEDA_BaseScreen pointer.
** all sub-sheets in a given schematic must have different names to generate a meaningful netlist.
=======
2008-Feb-12 UPDATE Igor Plyatov <plyatov@mail.ru>
================================================================================
+eeschema
......@@ -26,6 +35,7 @@ email address.
+all
Russian translation update.
2008-Feb-11 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
+pcbnew
......
......@@ -213,6 +213,7 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const
{
text << wxT( " [" ) << net->m_Netname << wxT( "]" );
}
text << wxChar(' ') << _("Net:") << via->GetNet();
if( shape != VIA_THROUGH )
{
......
......@@ -76,6 +76,7 @@ namespace DSN {
//-----<SPECCTRA_DB>-------------------------------------------------
#if !defined(STANDALONE)
void SPECCTRA_DB::buildLayerMaps( BOARD* aBoard )
{
......@@ -100,6 +101,7 @@ void SPECCTRA_DB::buildLayerMaps( BOARD* aBoard )
layerIds.push_back( CONV_TO_UTF8( aBoard->GetLayerName( kilayer ) ) );
}
}
#endif
int SPECCTRA_DB::findLayerName( const std::string& aLayerName ) const
......@@ -183,13 +185,21 @@ void SPECCTRA_DB::needRIGHT() throw( IOError )
expecting( T_RIGHT );
}
void SPECCTRA_DB::needSYMBOL() throw( IOError )
DSN_T SPECCTRA_DB::needSYMBOL() throw( IOError )
{
DSN_T tok = nextTok();
if( !isSymbol( tok ) )
expecting( T_SYMBOL );
return tok;
}
DSN_T SPECCTRA_DB::needSYMBOLorNUMBER() throw( IOError )
{
DSN_T tok = nextTok();
if( !isSymbol( tok ) && tok!=T_NUMBER )
expecting( "symbol|number" );
return tok;
}
void SPECCTRA_DB::readCOMPnPIN( std::string* component_id, std::string* pin_id ) throw( IOError )
{
......@@ -468,6 +478,8 @@ void SPECCTRA_DB::doPCB( PCB* growth ) throw( IOError )
void SPECCTRA_DB::doPARSER( PARSER* growth ) throw( IOError )
{
DSN_T tok;
std::string const1;
std::string const2;
/* <parser_descriptor >::=
(parser
......@@ -519,17 +531,19 @@ void SPECCTRA_DB::doPARSER( PARSER* growth ) throw( IOError )
break;
case T_host_version:
needSYMBOL();
needSYMBOLorNUMBER();
growth->host_version = lexer->CurText();
needRIGHT();
break;
case T_constant:
needSYMBOL();
growth->const_id1 = lexer->CurText();
needSYMBOL();
growth->const_id2 = lexer->CurText();
needSYMBOLorNUMBER();
const1 = lexer->CurText();
needSYMBOLorNUMBER();
const2 = lexer->CurText();
needRIGHT();
growth->constants.push_back( const1 );
growth->constants.push_back( const2 );
break;
case T_write_resolution: // [(writee_resolution {<character> <positive_integer >})]
......@@ -710,6 +724,8 @@ void SPECCTRA_DB::doSTRUCTURE( STRUCTURE* growth ) throw(IOError)
break;
case T_layer_noise_weight:
if( growth->layer_noise_weight )
unexpected( tok );
growth->layer_noise_weight = new LAYER_NOISE_WEIGHT( growth );
doLAYER_NOISE_WEIGHT( growth->layer_noise_weight );
break;
......@@ -755,11 +771,15 @@ L_place:
break;
case T_via:
if( growth->via )
unexpected( tok );
growth->via = new VIA( growth );
doVIA( growth->via );
break;
case T_control:
if( growth->control )
unexpected( tok );
growth->control = new CONTROL( growth );
doCONTROL( growth->control );
break;
......@@ -772,11 +792,15 @@ L_place:
break;
case T_rule:
if( growth->rules )
unexpected( tok );
growth->rules = new RULE( growth, T_rule );
doRULE( growth->rules );
break;
case T_place_rule:
if( growth->place_rules )
unexpected( tok );
growth->place_rules = new RULE( growth, T_place_rule );
doRULE( growth->place_rules );
break;
......@@ -2219,7 +2243,8 @@ void SPECCTRA_DB::doPIN( PIN* growth ) throw( IOError )
growth->padstack_id = lexer->CurText();
tok = nextTok();
while( (tok = nextTok()) != T_RIGHT )
{
if( tok == T_LEFT )
{
tok = nextTok();
......@@ -2230,9 +2255,9 @@ void SPECCTRA_DB::doPIN( PIN* growth ) throw( IOError )
expecting( T_NUMBER );
growth->SetRotation( strtod( lexer->CurText(), 0 ) );
needRIGHT();
tok = nextTok();
}
else
{
if( !isSymbol(tok) && tok!=T_NUMBER )
expecting( "pin_id" );
......@@ -2245,9 +2270,8 @@ void SPECCTRA_DB::doPIN( PIN* growth ) throw( IOError )
if( nextTok() != T_NUMBER )
expecting( T_NUMBER );
growth->vertex.y = strtod( lexer->CurText(), 0 );
if( nextTok() != T_RIGHT )
unexpected( lexer->CurText() );
}
}
}
......@@ -2286,8 +2310,8 @@ void SPECCTRA_DB::doLIBRARY( LIBRARY* growth ) throw( IOError )
case T_padstack:
PADSTACK* padstack;
padstack = new PADSTACK( growth );
growth->padstacks.push_back( padstack );
padstack = new PADSTACK();
growth->AddPadstack( padstack );
doPADSTACK( padstack );
break;
......@@ -2308,6 +2332,7 @@ void SPECCTRA_DB::doLIBRARY( LIBRARY* growth ) throw( IOError )
void SPECCTRA_DB::doNET( NET* growth ) throw( IOError )
{
DSN_T tok = nextTok();
PIN_REFS* pin_refs;
/* <net_descriptor >::=
(net <net_id >
......@@ -2358,14 +2383,38 @@ void SPECCTRA_DB::doNET( NET* growth ) throw( IOError )
case T_pins:
case T_order:
growth->pins_type = tok;
pin_refs = &growth->pins;
goto L_pins;
case T_expose:
pin_refs = &growth->expose;
goto L_pins;
case T_noexpose:
pin_refs = &growth->noexpose;
goto L_pins;
case T_source:
pin_refs = &growth->source;
goto L_pins;
case T_load:
pin_refs = &growth->load;
goto L_pins;
case T_terminator:
pin_refs = &growth->terminator;
//goto L_pins;
L_pins:
{
PIN_REF empty( growth );
while( (tok = nextTok()) != T_RIGHT )
{
// copy the empty one, then fill its copy later thru pin_ref.
growth->pins.push_back( empty );
pin_refs->push_back( empty );
PIN_REF* pin_ref = &growth->pins.back();
PIN_REF* pin_ref = &pin_refs->back();
readCOMPnPIN( &pin_ref->component_id, &pin_ref->pin_id );
}
......@@ -3431,7 +3480,7 @@ const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote
if( strlen(wrapee)==0 )
return quote_char;
bool isNumber = true;
// bool isNumber = true;
for( ; *wrapee; ++wrapee )
{
......@@ -3444,12 +3493,12 @@ const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee, const char* quote
if( strchr( quoteThese, *wrapee ) )
return quote_char;
if( !strchr( "01234567890.-+", *wrapee ) )
isNumber = false;
// if( !strchr( "01234567890.-+", *wrapee ) )
// isNumber = false;
}
if( isNumber )
return quote_char;
// if( isNumber )
// return quote_char;
return ""; // can use an unwrapped string.
}
......@@ -3670,6 +3719,11 @@ int ELEM_HOLDER::FindElem( DSN_T aType, int instanceNum )
return -1;
}
// a reasonably small memory price to pay for improved performance
STRINGFORMATTER ELEM::sf;
//-----<UNIT_RES>---------------------------------------------------------
UNIT_RES UNIT_RES::Default( NULL, T_resolution );
......@@ -3679,6 +3733,8 @@ UNIT_RES UNIT_RES::Default( NULL, T_resolution );
int PADSTACK::Compare( PADSTACK* lhs, PADSTACK* rhs )
{
// printf( "PADSTACK::Compare( %p, %p)\n", lhs, rhs );
if( !lhs->hash.size() )
lhs->hash = lhs->makeHash();
......@@ -3725,7 +3781,6 @@ int COMPONENT::Compare( COMPONENT* lhs, COMPONENT* rhs )
*/
//-----<PARSER>-----------------------------------------------------------
PARSER::PARSER( ELEM* aParent ) :
ELEM( T_parser, aParent )
{
......@@ -3752,10 +3807,17 @@ void PARSER::FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOErro
out->Print( nestLevel, "(host_cad \"%s\")\n", host_cad.c_str() );
out->Print( nestLevel, "(host_version \"%s\")\n", host_version.c_str() );
if( const_id1.length()>0 || const_id2.length()>0 )
out->Print( nestLevel, "(constant %c%s%c %c%s%c)\n",
string_quote, const_id1.c_str(), string_quote,
string_quote, const_id2.c_str(), string_quote );
for( STRINGS::iterator i=constants.begin(); i!=constants.end(); )
{
const std::string& s1 = *i++;
const std::string& s2 = *i++;
const char* q1 = out->GetQuoteChar( s1.c_str() );
const char* q2 = out->GetQuoteChar( s2.c_str() );
out->Print( nestLevel, "(constant %s%s%s %s%s%s)\n",
q1, s1.c_str(), q1,
q2, s2.c_str(), q2 );
}
if( routes_include_testpoint || routes_include_guides || routes_include_image_conductor )
out->Print( nestLevel, "(routes_include%s%s%s)\n",
......
......@@ -29,6 +29,10 @@
// see http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html
#include <boost/ptr_container/ptr_vector.hpp>
// see http://www.boost.org/libs/ptr_container/doc/ptr_set.html
#include <boost/ptr_container/ptr_set.hpp>
#include <boost/noncopyable.hpp>
#include "fctsys.h"
#include "dsn.h"
......@@ -303,14 +307,16 @@ protected:
*/
std::string makeHash()
{
STRINGFORMATTER sf;
sf.Clear();
FormatContents( &sf, 0 );
sf.StripUseless();
return sf.GetString();
}
// avoid creating this for every compare, make static.
static STRINGFORMATTER sf;
public:
......@@ -466,8 +472,8 @@ class PARSER : public ELEM
bool via_rotate_first;
bool generated_by_freeroute;
std::string const_id1;
std::string const_id2;
/// This holds pairs of strings, one pair for each constant definition
STRINGS constants;
std::string host_cad;
std::string host_version;
......@@ -1924,12 +1930,16 @@ class PIN : public ELEM
std::string pin_id;
POINT vertex;
int kiNetCode; ///< kicad netcode
public:
PIN( ELEM* aParent ) :
ELEM( T_pin, aParent )
{
rotation = 0.0;
isRotated = false;
kiNetCode = 0;
}
void SetRotation( double aRotation )
......@@ -1960,6 +1970,8 @@ public:
vertex.x, vertex.y );
}
};
typedef boost::ptr_vector<PIN> PINS;
class LIBRARY;
class IMAGE : public ELEM_HOLDER
......@@ -1978,7 +1990,6 @@ class IMAGE : public ELEM_HOLDER
the kids list.
*/
typedef boost::ptr_vector<PIN> PINS;
PINS pins;
RULE* rules;
......@@ -2085,7 +2096,7 @@ typedef boost::ptr_vector<IMAGE> IMAGES;
* Class PADSTACK
* holds either a via or a pad definition.
*/
class PADSTACK : public ELEM_HOLDER
class PADSTACK : public ELEM_HOLDER, private boost::noncopyable
{
friend class SPECCTRA_DB;
......@@ -2105,8 +2116,14 @@ class PADSTACK : public ELEM_HOLDER
public:
PADSTACK( ELEM* aParent ) :
ELEM_HOLDER( T_padstack, aParent )
/**
* Constructor PADSTACK()
* cannot take ELEM* aParent because PADSTACKSET confuses this with a
* copy constructor and causes havoc. Instead set parent with
* LIBRARY::AddPadstack()
*/
PADSTACK() :
ELEM_HOLDER( T_padstack, NULL )
{
unit = 0;
rotate = T_on;
......@@ -2131,6 +2148,7 @@ public:
*/
static int Compare( PADSTACK* lhs, PADSTACK* rhs );
void SetPadstackId( const char* aPadstackId )
{
padstack_id = aPadstackId;
......@@ -2194,6 +2212,15 @@ public:
};
typedef boost::ptr_vector<PADSTACK> PADSTACKS;
/**
* Function operator<()
* is used by the PADSTACKSET boost::ptr_set below
*/
inline bool operator<( const PADSTACK& lhs, const PADSTACK& rhs )
{
return PADSTACK::Compare( (PADSTACK*) &lhs, (PADSTACK*) &rhs ) < 0;
}
/**
* Class LIBRARY
......@@ -2228,6 +2255,7 @@ public:
void AddPadstack( PADSTACK* aPadstack )
{
aPadstack->SetParent( this );
padstacks.push_back( aPadstack );
}
......@@ -2537,10 +2565,15 @@ class NET : public ELEM
bool unassigned;
int net_number;
DSN_T pins_type; ///< T_pins | T_order
DSN_T pins_type; ///< T_pins | T_order, type of field 'pins' below
PIN_REFS pins;
PIN_REFS expose;
PIN_REFS noexpose;
PIN_REFS source;
PIN_REFS load;
PIN_REFS terminator;
DSN_T type; ///< T_fix | T_normal
DSN_T supply; ///< T_power | T_ground
......@@ -3525,6 +3558,9 @@ public:
};
typedef boost::ptr_set<PADSTACK> PADSTACKSET;
/**
* Class SPECCTRA_DB
* holds a DSN data tree, usually coming from a DSN file.
......@@ -3561,6 +3597,12 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
static const KICAD_T scanPADs[];
PADSTACKSET padstackset;
/// we don't want ownership here permanently, so we don't use boost::ptr_vector
std::vector<NET*> nets;
/**
* Function buildLayerMaps
* creates a few data translation structures for layer name and number
......@@ -3612,9 +3654,20 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
* calls nextTok() and then verifies that the token read in
* satisfies bool isSymbol().
* If not, an IOError is thrown.
* @return DSN_T - the actual token read in.
* @throw IOError, if the next token does not satisfy isSymbol()
*/
void needSYMBOL() throw( IOError );
DSN_T needSYMBOL() throw( IOError );
/**
* Function needSYMBOLorNUMBER
* calls nextTok() and then verifies that the token read in
* satisfies bool isSymbol() or tok==T_NUMBER.
* If not, an IOError is thrown.
* @return DSN_T - the actual token read in.
* @throw IOError, if the next token does not satisfy the above test
*/
DSN_T needSYMBOLorNUMBER() throw( IOError );
/**
* Function readCOMPnPIN
......@@ -3718,28 +3771,35 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
/**
* Function makeIMAGE
* allocates an IMAGE on the heap and creates all the PINs according
* to the PADs in the MODULE.
* to the D_PADs in the MODULE.
* @param aBoard The owner of the MODULE.
* @param aModule The MODULE from which to build the IMAGE.
* @return IMAGE* - not tested for duplication yet.
*/
IMAGE* makeIMAGE( MODULE* aModule );
IMAGE* makeIMAGE( BOARD* aBoard, MODULE* aModule );
/**
* Function makePADSTACKs
* makes all the PADSTACKs, and marks each D_PAD with the index into the
* LIBRARY::padstacks list that it matches.
* Function makePADSTACK
* creates a PADSTACK which matches the given pad. Only pads which do not
* satisfy the function isKeepout() should be passed to this function.
* @param aPad The D_PAD which needs to be made into a PADSTACK.
* @return PADSTACK* - The created padstack, including its padstack_id.
*/
void makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads );
PADSTACK* makePADSTACK( BOARD* aBoard, D_PAD* aPad );
/**
* Function makeVia
* makes a round through hole PADSTACK using the given Kicad diameter in deci-mils.
* @param aCopperDiameter The diameter of the copper pad.
* @param aDrillDiameter The drill diameter, used on re-import of the session file.
* @param aTopLayer The DSN::PCB top most layer index.
* @param aBotLayer The DSN::PCB bottom most layer index.
* @return PADSTACK* - The padstack, which is on the heap only, user must save
* or delete it.
*/
PADSTACK* makeVia( int aCopperDiameter, int aDrillDiameter );
PADSTACK* makeVia( int aCopperDiameter, int aDrillDiameter,
int aTopLayer, int aBotLayer );
/**
* Function makeVia
......@@ -3751,6 +3811,19 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
PADSTACK* makeVia( const SEGVIA* aVia );
/**
* Function deleteNETs
* deletes all the NETs that may be in here.
*/
void deleteNETs()
{
for( unsigned n=0; n<nets.size(); ++n )
delete nets[n];
nets.clear();
}
//-----<FromSESSION>-----------------------------------------------------
/**
......@@ -3786,6 +3859,8 @@ public:
delete pcb;
delete session;
deleteNETs();
if( fp )
fclose( fp );
}
......
......@@ -40,7 +40,9 @@
#include "trigo.h" // RotatePoint()
#include <set> // std::set
#include <map> // std::map
#include <boost/utility.hpp> // boost::addressof()
using namespace DSN;
......@@ -286,15 +288,15 @@ static bool isKeepout( D_PAD* aPad )
}
/**************************************************************************/
/*
static int Pad_list_Sort_by_Shapes( const void* refptr, const void* objptr )
/**************************************************************************/
{
const D_PAD* padref = *(D_PAD**)refptr;
const D_PAD* padcmp = *(D_PAD**)objptr;
return D_PAD::Compare( padref, padcmp );
}
*/
/**
......@@ -312,246 +314,52 @@ static PATH* makePath( const POINT& aStart, const POINT& aEnd, const std::string
}
IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule )
{
PADSTACKS& padstacks = pcb->library->padstacks;
TYPE_COLLECTOR pads;
// get all the MODULE's pads.
pads.Collect( aModule, scanPADs );
IMAGE* image = new IMAGE(0);
image->image_id = CONV_TO_UTF8( aModule->m_LibRef );
// from the pads, and make an IMAGE using collated padstacks.
for( int p=0; p<pads.GetCount(); ++p )
{
D_PAD* pad = (D_PAD*) pads[p];
// see if this pad is a through hole with no copper on its perimeter
if( isKeepout( pad ) )
{
KEEPOUT* keepout = new KEEPOUT(image, T_keepout);
image->keepouts.push_back( keepout );
CIRCLE* circle = new CIRCLE(keepout);
keepout->SetShape( circle );
circle->SetDiameter( scale(pad->m_Drill.x) );
circle->SetVertex( mapPt( pad->m_Pos0 ) );
circle->layer_id = "signal";
}
else
{
PADSTACK* padstack = &padstacks[pad->m_logical_connexion];
PIN* pin = new PIN(image);
image->pins.push_back( pin );
pin->padstack_id = padstack->padstack_id;
pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() );
wxPoint pos( pad->m_Pos0 );
wxPoint offset( pad->m_Offset.x, pad->m_Offset.y );
int angle = pad->m_Orient - aModule->m_Orient; // tenths of degrees
if( angle )
{
NORMALIZE_ANGLE_POS(angle);
pin->SetRotation( angle / 10.0 );
if( pad->m_Offset.x || pad->m_Offset.y )
{
RotatePoint( &offset, angle );
}
}
pos += offset;
pin->SetVertex( mapPt( pos ) );
}
}
return image;
}
PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
{
CIRCLE* circle;
SHAPE* shape;
double dsnDiameter;
char name[48];
PADSTACK* padstack = new PADSTACK( pcb->library );
switch( aVia->Shape() )
{
case VIA_THROUGH:
shape = new SHAPE( padstack );
padstack->Append( shape );
circle = new CIRCLE( shape );
shape->SetShape( circle );
dsnDiameter = scale( aVia->m_Width );
circle->SetDiameter( dsnDiameter );
circle->SetLayerId( "signal" );
snprintf( name, sizeof(name), "Via[A]%.6g:%.6g_mil", dsnDiameter,
// encode the drill value into the name for later import
scale( aVia->GetDrillValue() ) );
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
break;
case VIA_BLIND_BURIED:
case VIA_MICROVIA:
int topLayer;
int botLayer;
aVia->ReturnLayerPair( &topLayer, &botLayer );
topLayer = kicadLayer2pcb[topLayer];
botLayer = kicadLayer2pcb[botLayer];
if( topLayer > botLayer )
EXCHG( topLayer, botLayer );
dsnDiameter = scale( aVia->m_Width );
for( int layer=topLayer; layer<=botLayer; ++layer )
{
shape = new SHAPE( padstack );
padstack->Append( shape );
circle = new CIRCLE( shape );
shape->SetShape( circle );
circle->SetDiameter( dsnDiameter );
circle->SetLayerId( layerIds[layer].c_str() );
}
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_mil",
topLayer, botLayer, dsnDiameter,
// encode the drill value into the name for later import
scale( aVia->GetDrillValue() )
);
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
break;
}
return padstack;
}
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter )
{
char name[48];
PADSTACK* padstack = new PADSTACK( pcb->library );
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle );
double dsnDiameter = scale(aCopperDiameter);
circle->SetDiameter( dsnDiameter );
circle->SetLayerId( "signal" );
snprintf( name, sizeof(name), "Via[A]%.6g:%.6g_mil", dsnDiameter,
// encode the drill value into the name for later import
scale( aDrillDiameter ) );
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
return padstack;
}
/**
* Struct ltWX
* is used secretly by the std:set<> class below. See STRINGSET typedef.
* Struct wxString_less_than_
* is used the std:set<> and std::map<> instantiations below.
* See STRINGSET typedef and PINMAP typedef below.
*/
struct ltWX
struct wxString_less_than
{
// a "less than" test on two wxStrings, by pointer.
bool operator()( const wxString* s1, const wxString* s2) const
bool operator()( const wxString& s1, const wxString& s2) const
{
return s1->Cmp( *s2 ) < 0; // case specific wxString compare
return s1.Cmp( s2 ) < 0; // case specific wxString compare
}
};
void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
/**
* Function makePADSTACK
* creates a PADSTACK which matches the given pad. Only pads which do not
* satisfy the function isKeepout() should be passed to this function.
* @param aPad The D_PAD which needs to be made into a PADSTACK.
* @return PADSTACK* - The created padstack, including its padstack_id.
*/
PADSTACK* SPECCTRA_DB::makePADSTACK( BOARD* aBoard, D_PAD* aPad )
{
char name[80]; // padstack name builder
std::string uniqifier;
if( aPads.GetCount() )
{
qsort( (void*) aPads.BasePtr(), aPads.GetCount(), sizeof(D_PAD*), Pad_list_Sort_by_Shapes );
}
D_PAD* old_pad = NULL;
for( int i=0; i<aPads.GetCount(); ++i )
{
D_PAD* pad = (D_PAD*) aPads[i];
bool doLayer[2] = { // top and bottom layers only
pad->IsOnLayer( LAYER_CMP_N ),
pad->IsOnLayer( COPPER_LAYER_N )
aPad->IsOnLayer( LAYER_CMP_N ),
aPad->IsOnLayer( COPPER_LAYER_N )
};
if( old_pad && 0==D_PAD::Compare( old_pad, pad ) )
{
// padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
pad->m_logical_connexion = pcb->library->padstacks.size()-1;
// this is the same as the last pad, so do not add it to the padstack list.
continue;
}
// if pad has no copper presence, then it will be made into
// an "image->keepout" later. No copper pad here, it is probably a hole.
if( (!doLayer[0] && !doLayer[1]) || isKeepout( pad ) )
{
continue;
}
old_pad = pad;
// caller must do this screen before calling here.
wxASSERT( !isKeepout( aPad ) );
PADSTACK* padstack = new PADSTACK( pcb->library );
pcb->library->AddPadstack( padstack );
wxASSERT( doLayer[0] || doLayer[1] );
// padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
pad->m_logical_connexion = pcb->library->padstacks.size()-1;
PADSTACK* padstack = new PADSTACK();
/* Through hole pads are reported on the <reserved_layer_name>
"signal". Reporting through hole pads on the special
"signal" layer may have problems when power layers are in the layer
stack. See bottom of page 74 of the SECCTRA Design Language
Reference, May 2000. We could do better if there was actually a
"layer type" field within Kicad which would hold one of: T_signal,
T_power, T_mixed, T_jumper.
PAD_SMD and PAD_CONN are reported on each layer for which
they are present.
*/
int reportedLayers; // how many in reported padstack
int reportedLayers = 0; // how many in reported padstack
const char* layerName[NB_COPPER_LAYERS];
static const char signal[] = "signal";
if( pad->m_Attribut==PAD_SMD || pad->m_Attribut==PAD_CONN )
if( aPad->m_Attribut==PAD_SMD || aPad->m_Attribut==PAD_CONN )
{
reportedLayers = 0;
// PAD_SMD and PAD_CONN are reported on each layer for which
// they are present.
uniqifier = '[';
if( doLayer[0] )
......@@ -568,19 +376,41 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
uniqifier += ']';
}
else
else // through hole pad
{
#if 0
/* Through hole pads are reported on the <reserved_layer_name>
"signal". Reporting through hole pads on the special
"signal" layer may have problems when power layers are in the layer
stack. See bottom of page 74 of the SECCTRA Design Language
Reference, May 2000. We could do better if there was actually a
"layer type" field within Kicad which would hold one of: T_signal,
T_power, T_mixed, T_jumper.
*/
reportedLayers = 1;
layerName[0] = signal;
uniqifier = "[A]"; // A for all
#else
// Through hole pads are reported on *all* copper layers.
int copperLayers = aBoard->GetCopperLayerCount();
for( int layer=0; layer<copperLayers; ++layer )
{
layerName[reportedLayers++] = layerIds[layer].c_str();
}
uniqifier = "[A]"; // A for all
#endif
}
switch( pad->m_PadShape )
switch( aPad->m_PadShape )
{
default:
case PAD_CIRCLE:
{
double diameter = scale(pad->m_Size.x);
double diameter = scale(aPad->m_Size.x);
for( int ndx=0; ndx<reportedLayers; ++ndx )
{
......@@ -595,21 +425,16 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
}
snprintf( name, sizeof(name), "Round%sPad_%.6g_mil",
uniqifier.c_str(), scale(pad->m_Size.x) );
uniqifier.c_str(), scale(aPad->m_Size.x) );
name[ sizeof(name)-1 ] = 0;
// @todo verify that all pad names are unique, there is a chance that
// D_PAD::Compare() could say two pads are different, yet the get the same
// name here. If so, blend in the padNdx into the name.
padstack->SetPadstackId( name );
}
break;
case PAD_RECT:
{
double dx = scale( pad->m_Size.x ) / 2.0;
double dy = scale( pad->m_Size.y ) / 2.0;
double dx = scale( aPad->m_Size.x ) / 2.0;
double dy = scale( aPad->m_Size.y ) / 2.0;
POINT lowerLeft( -dx, -dy );
POINT upperRight( dx, dy );
......@@ -627,21 +452,17 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
}
snprintf( name, sizeof(name), "Rect%sPad_%.6gx%.6g_mil",
uniqifier.c_str(), scale(pad->m_Size.x), scale(pad->m_Size.y) );
uniqifier.c_str(), scale(aPad->m_Size.x), scale(aPad->m_Size.y) );
name[ sizeof(name)-1 ] = 0;
// @todo verify that all pad names are unique, there is a chance that
// D_PAD::Compare() could say two pads are different, yet they get the same
// name here. If so, blend in the padNdx into the name.
padstack->SetPadstackId( name );
}
break;
case PAD_OVAL:
{
double dx = scale( pad->m_Size.x ) / 2.0;
double dy = scale( pad->m_Size.y ) / 2.0;
double dx = scale( aPad->m_Size.x ) / 2.0;
double dy = scale( aPad->m_Size.y ) / 2.0;
double dr = dx - dy;
if( dr >= 0 ) // oval is horizontal
......@@ -680,13 +501,9 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
}
snprintf( name, sizeof(name), "Oval%sPad_%.6gx%.6g_mil",
uniqifier.c_str(), scale(pad->m_Size.x), scale(pad->m_Size.y) );
uniqifier.c_str(), scale(aPad->m_Size.x), scale(aPad->m_Size.y) );
name[ sizeof(name)-1 ] = 0;
// @todo verify that all pad names are unique, there is a chance that
// D_PAD::Compare() could say two pads are different, yet they get the same
// name here. If so, blend in the padNdx into the name.
padstack->SetPadstackId( name );
}
break;
......@@ -696,40 +513,182 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
break;
*/
}
return padstack;
}
/// data type used to ensure unique-ness of pin names
typedef std::map<wxString, int, wxString_less_than> PINMAP;
typedef std::pair<const wxString, int> PINMAP_PAIR;
IMAGE* SPECCTRA_DB::makeIMAGE( BOARD* aBoard, MODULE* aModule )
{
PINMAP pinmap;
TYPE_COLLECTOR pads;
wxString padName;
// get all the MODULE's pads.
pads.Collect( aModule, scanPADs );
IMAGE* image = new IMAGE(0);
image->image_id = CONV_TO_UTF8( aModule->m_LibRef );
// from the pads, and make an IMAGE using collated padstacks.
for( int p=0; p<pads.GetCount(); ++p )
{
D_PAD* pad = (D_PAD*) pads[p];
// see if this pad is a through hole with no copper on its perimeter
if( isKeepout( pad ) )
{
double diameter = scale( pad->m_Drill.x );
POINT vertex = mapPt( pad->m_Pos0 );
int layerCount = aBoard->GetCopperLayerCount();
for( int layer=0; layer<layerCount; ++layer )
{
KEEPOUT* keepout = new KEEPOUT(image, T_keepout);
image->keepouts.push_back( keepout );
CIRCLE* circle = new CIRCLE( keepout );
keepout->SetShape( circle );
circle->SetDiameter( diameter );
circle->SetVertex( vertex );
circle->SetLayerId( layerIds[layer].c_str() );
}
}
else
{
PADSTACK* padstack = makePADSTACK( aBoard, pad );
// unique pads are now in the padstack list.
// next we add the via's which may be used.
PADSTACKSET::iterator iter = padstackset.find( *padstack );
if( iter != padstackset.end() )
{
// padstack is a duplicate, delete it and use the original
delete padstack;
padstack = (PADSTACK*) *iter.base(); // folk lore, becareful here
}
else
{
padstackset.insert( padstack );
}
int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize;
if( defaultViaSize )
PIN* pin = new PIN(image);
padName = pad->ReturnStringPadName();
pin->pin_id = CONV_TO_UTF8( padName );
if( padName!=wxEmptyString && pinmap.find( padName )==pinmap.end() )
{
PADSTACK* padstack = makeVia( defaultViaSize, g_DesignSettings.m_ViaDrill );
pcb->library->AddPadstack( padstack );
pinmap[ padName ] = 0;
}
else
{
char buf[32];
// remember this index, it is the default via and also the start of the
// vias within the padstack list. Before this index are the pads.
// At this index and later are the vias.
pcb->library->SetViaStartIndex( pcb->library->padstacks.size()-1 );
int duplicates = ++pinmap[ padName ];
sprintf( buf, "@%d", duplicates );
// padstack->SetPadstackId( "Via_Default" ); I like the padstack_id with the size in it.
pin->pin_id += buf; // append "@1" or "@2", etc. to pin name
}
for( int i=0; i<HISTORY_NUMBER; ++i )
pin->kiNetCode = pad->GetNet();
image->pins.push_back( pin );
pin->padstack_id = padstack->padstack_id;
wxPoint pos( pad->m_Pos0 );
wxPoint offset( pad->m_Offset.x, pad->m_Offset.y );
int angle = pad->m_Orient - aModule->m_Orient; // tenths of degrees
if( angle )
{
int viaSize = aBoard->m_BoardSettings->m_ViaSizeHistory[i];
if( !viaSize )
break;
NORMALIZE_ANGLE_POS(angle);
pin->SetRotation( angle / 10.0 );
if( viaSize == defaultViaSize )
continue;
if( pad->m_Offset.x || pad->m_Offset.y )
{
RotatePoint( &offset, angle );
}
}
PADSTACK* padstack = makeVia( viaSize, g_DesignSettings.m_ViaDrill );
pcb->library->AddPadstack( padstack );
pos += offset;
pin->SetVertex( mapPt( pos ) );
}
}
return image;
}
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter,
int aTopLayer, int aBotLayer )
{
char name[48];
PADSTACK* padstack = new PADSTACK();
double dsnDiameter = scale(aCopperDiameter);
for( int layer=aTopLayer; layer<=aBotLayer; ++layer )
{
SHAPE* shape = new SHAPE( padstack );
padstack->Append( shape );
CIRCLE* circle = new CIRCLE( shape );
shape->SetShape( circle );
circle->SetDiameter( dsnDiameter );
circle->SetLayerId( layerIds[layer].c_str() );
}
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_mil",
aTopLayer, aBotLayer, dsnDiameter,
// encode the drill value into the name for later import
scale( aDrillDiameter )
);
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
return padstack;
}
PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
{
int topLayer;
int botLayer;
aVia->ReturnLayerPair( &topLayer, &botLayer );
topLayer = kicadLayer2pcb[topLayer];
botLayer = kicadLayer2pcb[botLayer];
if( topLayer > botLayer )
EXCHG( topLayer, botLayer );
return makeVia( aVia->m_Width, aVia->GetDrillValue(), topLayer, botLayer );
}
#if 0
void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
{
}
#endif
typedef std::set<wxString, wxString_less_than> STRINGSET;
typedef std::pair<STRINGSET::iterator, bool> STRINGSET_PAIR;
void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
{
TYPE_COLLECTOR items;
......@@ -740,14 +699,15 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
// Not all boards are exportable. Check that all reference Ids are unique.
// Unless they are unique, we cannot import the session file which comes
// back to us later from the router.
// back to us later from the router. Also check that all pad names within
// a part are unique, otherwise Electra and Freerouter will not draw the
// pads properly.
{
items.Collect( aBoard, scanMODULEs );
TYPE_COLLECTOR padItems;
typedef std::set<const wxString*, ltWX> STRINGSET;
typedef std::pair<STRINGSET::iterator, bool> PAIR;
items.Collect( aBoard, scanMODULEs );
STRINGSET references; // holds unique component references
STRINGSET refs; // holds module reference designators
for( int i=0; i<items.GetCount(); ++i )
{
......@@ -760,8 +720,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
}
// if we cannot insert OK, that means the reference has been seen before.
PAIR pair = references.insert( &module->GetReference() );
if( !pair.second ) // insert failed
STRINGSET_PAIR refpair = refs.insert( module->GetReference() );
if( !refpair.second ) // insert failed
{
ThrowIOError( _("Multiple components have identical reference IDs of \"%s\"."),
module->GetReference().GetData() );
......@@ -785,11 +745,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
}
}
// Since none of these statements cause any immediate output, the order
// of them is somewhat flexible. The outputting to disk is done at the
// end. We start by gathering all the layer information from the board.
//-----<layer_descriptor>-----------------------------------------------
{
// specctra wants top physical layer first, then going down to the
......@@ -818,10 +773,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
}
}
// for now, report on only the top and bottom layers with respect to the copper
// within a pad's padstack. this is usually correct, but not rigorous.
// a space in a quoted token is NOT a terminator, true establishes this.
pcb->parser->space_in_quoted_tokens = true;
......@@ -1004,49 +955,78 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
}
// keepouts could go here, there are none in Kicad at this time.
// although COPPER_PLANEs probably will need them for the thru holes, etc.
// but in that case they are WINDOWs within the COPPER_PLANEs.
//-----<build the initial padstack list>--------------------------------
//-----<build the images, components, and netlist>-----------------------
{
TYPE_COLLECTOR pads;
// get all the D_PADs into 'pads'.
pads.Collect( aBoard, scanPADs );
// find the highest numbered netCode within the board.
int highestNetCode = -1;
for( EQUIPOT* equipot = aBoard->m_Equipots; equipot; equipot = equipot->Next() )
highestNetCode = MAX( highestNetCode, equipot->GetNet() );
makePADSTACKs( aBoard, pads );
deleteNETs();
#if 0 && defined(DEBUG)
for( int p=0; p<pads.GetCount(); ++p )
pads[p]->Show( 0, std::cout );
#endif
}
// expand the net vector to highestNetCode+1, setting empty to NULL
nets.resize( highestNetCode+1, NULL );
// skip netcode = 0
for( unsigned i=1; i<nets.size(); ++i )
nets[i] = new NET( pcb->network );
//-----<build the images and components>---------------------------------
for( EQUIPOT* equipot = aBoard->m_Equipots; equipot; equipot = equipot->Next() )
{
int netcode = equipot->GetNet();
if( netcode > 0 )
nets[ netcode ]->net_id = CONV_TO_UTF8( equipot->m_Netname );
}
items.Collect( aBoard, scanMODULEs );
padstackset.clear();
for( int m=0; m<items.GetCount(); ++m )
{
MODULE* module = (MODULE*) items[m];
IMAGE* image = makeIMAGE( module );
IMAGE* image = makeIMAGE( aBoard, module );
// create a net list entry for all the actual pins in the image
// for the current module. location of this code is critical
// because we fabricated some pin names to ensure unique-ness
// of pin names within a module, do not move this code. The
// exported netlist will have some fabricated pin names in it.
// If you don't like fabricated pin names, then make sure all pads
// within your MODULEs are uniquely named!
PIN_REF empty( pcb->network );
for( unsigned p=0; p<image->pins.size(); ++p )
{
PIN* pin = &image->pins[p];
int netcode = pin->kiNetCode;
if( netcode > 0 )
{
NET* net = nets[netcode];
net->pins.push_back( empty );
PIN_REF& pin_ref = net->pins.back();
pin_ref.component_id = CONV_TO_UTF8( module->GetReference() );
pin_ref.pin_id = pin->pin_id;
}
}
IMAGE* registered = pcb->library->LookupIMAGE( image );
if( registered != image )
{
// If our new 'image' is not a unique IMAGE, delete it.
// In either case, 'registered' is the one we'll work with henceforth.
// and use the registered one, known as 'image' after this.
delete image;
image = registered;
}
// @todo: this only works if the user has not modified the MODULE within the PCB
// and made it different from what is in the PCBNEW library. Need to test
// each image for uniqueness, not just based on name as is done here:
COMPONENT* comp = pcb->placement->LookupCOMPONENT( registered->GetImageId() );
COMPONENT* comp = pcb->placement->LookupCOMPONENT( image->GetImageId() );
PLACE* place = new PLACE( comp );
comp->places.push_back( place );
......@@ -1060,69 +1040,73 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
if( module->flag )
{
int angle = 1800 - module->m_Orient;
NORMALIZE_ANGLE_POS(angle);
place->SetRotation( angle/10.0 );
place->side = T_back;
}
}
}
//-----<create the nets>------------------------------------------------
// copy the SPECCTRA_DB::padstackset to the LIBRARY. Since we are
// removing, do not increment the iterator
for( PADSTACKSET::iterator i=padstackset.begin(); i!=padstackset.end();
i=padstackset.begin() )
{
NETWORK* network = pcb->network;
TYPE_COLLECTOR nets;
TYPE_COLLECTOR pads;
static const KICAD_T scanNETs[] = { PCB_EQUIPOT_STRUCT_TYPE, EOT };
PADSTACKSET::auto_type ps = padstackset.release( i );
PADSTACK* padstack = ps.release();
nets.Collect( aBoard, scanNETs );
items.Collect( aBoard, scanMODULEs );
PIN_REF emptypin(0);
pcb->library->AddPadstack( padstack );
}
for( int n=0; n<nets.GetCount(); ++n )
// copy our SPECCTRA_DB::nets to the pcb->network
for( unsigned n=1; n<nets.size(); ++n )
{
EQUIPOT* kinet = (EQUIPOT*) nets[n];
if( kinet->GetNet() == 0 )
continue;
NET* net = nets[n];
if( net->pins.size() )
{
// give ownership to pcb->network
pcb->network->nets.push_back( net );
nets[n] = 0;
}
}
}
NET* net = new NET( network );
network->nets.push_back( net );
net->net_id = CONV_TO_UTF8( kinet->m_Netname );
net->net_number = kinet->GetNet();
//-----< output the vias >-----------------------------------------------
{
// ASSUME: unique pads are now in the padstack list! i.e. this code
// must follow the initial padstack construction code.
// Next we add the via's which may be used.
for( int m=0; m<items.GetCount(); ++m )
int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize;
if( defaultViaSize )
{
MODULE* module = (MODULE*) items[m];
PADSTACK* padstack = makeVia( defaultViaSize, g_DesignSettings.m_ViaDrill,
0, aBoard->GetCopperLayerCount()-1 );
pcb->library->AddPadstack( padstack );
pads.Collect( module, scanPADs );
// remember this index, it is the default via and also the start of the
// vias within the padstack list. Before this index are the pads.
// At this index and later are the vias.
pcb->library->SetViaStartIndex( pcb->library->padstacks.size()-1 );
}
for( int p=0; p<pads.GetCount(); ++p )
for( int i=0; i<HISTORY_NUMBER; ++i )
{
D_PAD* pad = (D_PAD*) pads[p];
int viaSize = aBoard->m_BoardSettings->m_ViaSizeHistory[i];
if( !viaSize )
break;
if( pad->GetNet() == kinet->GetNet() )
{
// push on an empty one, then fill it via 'pin_ref'
net->pins.push_back( emptypin );
PIN_REF* pin_ref = &net->pins.back();
if( viaSize == defaultViaSize )
continue;
pin_ref->SetParent( net );
pin_ref->component_id = CONV_TO_UTF8( module->GetReference() );
pin_ref->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() );
}
}
}
PADSTACK* padstack = makeVia( viaSize, g_DesignSettings.m_ViaDrill,
0, aBoard->GetCopperLayerCount()-1 );
pcb->library->AddPadstack( padstack );
}
}
#if 1 // do existing wires and vias
//-----<create the wires from tracks>-----------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment