specctra session work

This commit is contained in:
dickelbeck 2008-02-09 08:34:45 +00:00
parent 40e2fed36e
commit d47823c144
8 changed files with 543 additions and 321 deletions

View File

@ -5,6 +5,21 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with
email address.
2008-Feb-7 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
+pcbnew
added "const" to SEGVIA::GetDrillValue() const;
added GetDrillValue() to DRC instead of accessing SEGVIA::m_Drill directly.
changed specctra_export so it aborts if all reference designators are not
unique. Unless they are unique we cannot import the routed session. A
good example is the xylinx board which now fails to export.
first rough work on SEGVIA::makeVIA() but needs much more work. Simple
session files with vias at least import. Now encode drill diameter in
padstack name for later session import.
updated todo.txt file.
2008-Feb-7 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
+pcbnew

View File

@ -125,11 +125,13 @@ TRACK* TRACK::Copy() const
* calculate the drill value for vias (m-Drill if > 0, or default drill value for the board
* @return real drill_value
*/
int TRACK::GetDrillValue(void)
int TRACK::GetDrillValue() const
{
if ( Type() != TYPEVIA ) return 0;
if ( Type() != TYPEVIA )
return 0;
if ( m_Drill >= 0 ) return m_Drill;
if ( m_Drill >= 0 )
return m_Drill;
if ( m_Shape == VIA_MICROVIA )
return g_DesignSettings.m_MicroViaDrill;

View File

@ -173,7 +173,7 @@ public:
* calculate the drill value for vias (m-Drill if > 0, or default drill value for the board
* @return real drill_value
*/
int GetDrillValue(void);
int GetDrillValue() const;
/**
* Function ReturnMaskLayer

View File

@ -510,8 +510,7 @@ bool DRC::doTrackDrc( TRACK* aRefSeg, TRACK* aStart )
// This test seems necessary since the dialog box that displays the
// desired via hole size and width does not enforce a hole size smaller
// than the via's diameter.
if( aRefSeg->GetDrillValue() > aRefSeg->m_Width )
if( !aRefSeg->GetDrillValue() > aRefSeg->m_Width )
{
m_currentMarker = fillMarker( aRefSeg, NULL,
DRCE_VIA_HOLE_BIGGER, m_currentMarker );

View File

@ -2091,7 +2091,6 @@ class PADSTACK : public ELEM_HOLDER
std::string hash; ///< a hash string used by Compare(), not Format()ed/exported.
std::string padstack_id;
UNIT_RES* unit;
@ -2121,6 +2120,10 @@ public:
delete rules;
}
const std::string& GetPadstackId()
{
return padstack_id;
}
/**
* Function Compare
@ -2341,6 +2344,22 @@ public:
return &padstacks[ndx];
}
/**
* Function FindPADSTACK
* searches the padstack container by name.
* @return PADSTACK* - The PADSTACK with a matching name if it exists, else NULL.
*/
PADSTACK* FindPADSTACK( const std::string& aPadstackId )
{
for( unsigned i=0; i<padstacks.size(); ++i )
{
PADSTACK* ps = &padstacks[i];
if( 0 == ps->GetPadstackId().compare( aPadstackId ) )
return ps;
}
return NULL;
}
void FormatContents( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
if( unit )
@ -2888,6 +2907,11 @@ public:
supply = false;
}
const std::string& GetPadstackId()
{
return padstack_id;
}
void Format( OUTPUTFORMATTER* out, int nestLevel ) throw( IOError )
{
const char* quote = out->GetQuoteChar( padstack_id.c_str() );
@ -3711,10 +3735,11 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
* 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.
* @return PADSTACK* - The padstack, which is on the heap only, user must save
* or delete it.
*/
PADSTACK* makeVia( int aCopperDiameter );
PADSTACK* makeVia( int aCopperDiameter, int aDrillDiameter );
/**
* Function makeVia
@ -3734,6 +3759,9 @@ class SPECCTRA_DB : public OUTPUTFORMATTER
*/
TRACK* makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) throw( IOError );
SEGVIA* makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNetCode );
//-----</FromSESSION>----------------------------------------------------
public:
@ -3848,7 +3876,7 @@ public:
*
* @param aBoard The BOARD to convert to a PCB.
*/
void FromBOARD( BOARD* aBoard );
void FromBOARD( BOARD* aBoard ) throw( IOError );
/**

View File

@ -37,6 +37,7 @@
#include "wxPcbStruct.h" // Change_Side_Module()
#include "pcbstruct.h" // HISTORY_NUMBER
#include "autorout.h" // NET_CODES_OK
#include <set> // std::set
using namespace DSN;
@ -103,8 +104,12 @@ void WinEDA_PcbFrame::ExportToSpecctra( wxCommandEvent& event )
Affiche_Message( wxString( _("BOARD exported OK.")) );
}
else
{
errorText += '\n';
errorText += _("Unable to export, please fix and try again.");
DisplayError( this, errorText );
}
}
namespace DSN {
@ -268,6 +273,17 @@ static bool isRectangle( POINT_PAIRS& aList )
}
/**
* Function isKeepout
* decides if the pad is a copper less through hole which needs to be made into
* a round keepout.
*/
static bool isKeepout( D_PAD* aPad )
{
return aPad->m_PadShape==PAD_CIRCLE && aPad->m_Drill.x >= aPad->m_Size.x;
}
/**************************************************************************/
static int Pad_list_Sort_by_Shapes( const void* refptr, const void* objptr )
/**************************************************************************/
@ -313,7 +329,7 @@ IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule )
D_PAD* pad = (D_PAD*) pads[p];
// see if this pad is a through hole with no copper on its perimeter
if( pad->m_PadShape==PAD_CIRCLE && pad->m_Drill.x >= pad->m_Size.x )
if( isKeepout( pad ) )
{
KEEPOUT* keepout = new KEEPOUT(image, T_keepout);
image->keepouts.push_back( keepout );
@ -369,7 +385,9 @@ PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
circle->SetLayerId( "signal" );
snprintf( name, sizeof(name), "Via_%.6g_mil", dsnDiameter );
snprintf( name, sizeof(name), "Via_%.6g:%.6g_mil", dsnDiameter,
// encode the drill value in the name for later import
scale( aVia->GetDrillValue() ) );
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
break;
@ -398,7 +416,11 @@ PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
circle->SetLayerId( layerIds[layer].c_str() );
}
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g_mil", topLayer, botLayer, dsnDiameter );
snprintf( name, sizeof(name), "Via[%d-%d]_%.6g:%.6g_mil",
topLayer, botLayer, dsnDiameter,
// encode the drill value in the name for later import
scale( aVia->GetDrillValue() )
);
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
break;
@ -408,7 +430,7 @@ PADSTACK* SPECCTRA_DB::makeVia( const SEGVIA* aVia )
}
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter )
PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter, int aDrillDiameter )
{
char name[48];
PADSTACK* padstack = new PADSTACK( pcb->library );
@ -424,7 +446,9 @@ PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter )
circle->SetLayerId( "signal" );
snprintf( name, sizeof(name), "Via_%.6g_mil", dsnDiameter );
snprintf( name, sizeof(name), "Via_%.6g:%.6g_mil", dsnDiameter,
// encode the drill value in the name for later import
scale( aDrillDiameter ) );
name[ sizeof(name)-1 ] = 0;
padstack->SetPadstackId( name );
@ -432,6 +456,20 @@ PADSTACK* SPECCTRA_DB::makeVia( int aCopperDiameter )
}
/**
* Struct ltWX
* is used secretly by the std:set<> class below. See STRINGSET typedef.
*/
struct ltWX
{
// a "less than" test on two wxStrings, by pointer.
bool operator()( const wxString* s1, const wxString* s2) const
{
return s1->Cmp( *s2 ) < 0; // case specific wxString compare
}
};
void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
{
char name[80]; // padstack name builder
@ -464,10 +502,8 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
// 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])
|| (pad->m_PadShape==PAD_CIRCLE && pad->m_Drill.x >= pad->m_Size.x) )
if( (!doLayer[0] && !doLayer[1]) || isKeepout( pad ) )
{
// pad->m_logical_connexion = pcb->library->padstacks.size()-1;
continue;
}
@ -491,7 +527,7 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
they are present.
*/
int reportedLayers; // how many layers are reported.
int reportedLayers; // how many in reported padstack
const char* layerName[NB_COPPER_LAYERS];
static const char signal[] = "signal";
@ -652,7 +688,7 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
int defaultViaSize = aBoard->m_BoardSettings->m_CurrentViaSize;
if( defaultViaSize )
{
PADSTACK* padstack = makeVia( defaultViaSize );
PADSTACK* padstack = makeVia( defaultViaSize, g_DesignSettings.m_ViaDrill );
pcb->library->AddPadstack( padstack );
// remember this index, it is the default via and also the start of the
@ -672,13 +708,13 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
if( viaSize == defaultViaSize )
continue;
PADSTACK* padstack = makeVia( viaSize );
PADSTACK* padstack = makeVia( viaSize, g_DesignSettings.m_ViaDrill );
pcb->library->AddPadstack( padstack );
}
}
void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) throw( IOError )
{
TYPE_COLLECTOR items;
POINT_PAIRS ppairs;
@ -686,6 +722,36 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
static const KICAD_T scanMODULEs[] = { TYPEMODULE, EOT };
// 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.
{
items.Collect( aBoard, scanMODULEs );
typedef std::set<const wxString*, ltWX> STRINGSET;
typedef std::pair<STRINGSET::iterator, bool> PAIR;
STRINGSET references; // holds unique component references
for( int i=0; i<items.GetCount(); ++i )
{
MODULE* module = (MODULE*) items[i];
if( module->GetReference() == wxEmptyString )
{
ThrowIOError( _("Component with value of \"%s\" has empty reference id."),
module->GetValue().GetData() );
}
// if we cannot insert OK, that means the reference has been seen before.
PAIR pair = references.insert( &module->GetReference() );
if( !pair.second ) // insert failed
{
ThrowIOError( _("Multiple components have identical reference IDs of \"%s\"."),
module->GetReference().GetData() );
}
}
}
if( !pcb )
pcb = SPECCTRA_DB::MakePCB();
@ -703,8 +769,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
}
}
//pcb->placement->flip_style = T_rotate_first;
// 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.
@ -845,7 +909,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
//-----<rules>--------------------------------------------------------
{
// put out these rules, the user can then edit them with a text editor
char rule[80]; // padstack name builder
char rule[80];
int curTrackWidth = aBoard->m_BoardSettings->m_CurrentTrackWidth;
int curTrackClear = aBoard->m_BoardSettings->m_TrackClearence;
@ -879,7 +943,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
sprintf( rule, "(clearance %.6g (type smd_pin))", clearance );
rules.push_back( rule );
sprintf( rule, "(clearance %.6g (type smd_smd))", clearance );
sprintf( rule, "(clearance %.6g (type smd_smd))", clearance/4 );
rules.push_back( rule );
}
@ -905,8 +969,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
int count = item->m_Poly->corner.size();
for( int j=0; j<count; ++j )
{
wxPoint point( item->m_Poly->corner[j].x, item->m_Poly->corner[j].y );
wxPoint point( item->m_Poly->corner[j].x,
item->m_Poly->corner[j].y );
polygon->points.push_back( mapPt(point) );
}
@ -1044,12 +1108,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
items.Collect( aBoard, scanTRACKs );
/*
if( items.GetCount() )
qsort( (void*) items.BasePtr(), items.GetCount(),
sizeof(TRACK*), Track_list_Sort_by_Netcode );
*/
std::string netname;
WIRING* wiring = pcb->wiring;
PATH* path = 0;
@ -1105,7 +1163,7 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
}
//-----<export the existing real instantiated vias>---------------------
//-----<export the existing real BOARD instantiated vias>-----------------
{
// export all of them for now, later we'll decide what controls we need
// on this.

View File

@ -90,6 +90,12 @@ void WinEDA_PcbFrame::ImportSpecctraSession( wxCommandEvent& event )
catch( IOError ioe )
{
setlocale( LC_NUMERIC, "" ); // revert to the current locale
ioe.errorText += '\n';
ioe.errorText += _("BOARD may be corrupted, do not save it.");
ioe.errorText += '\n';
ioe.errorText += _("Fix problem and try again.");
DisplayError( this, ioe.errorText );
return;
}
@ -175,6 +181,76 @@ TRACK* SPECCTRA_DB::makeTRACK( PATH* aPath, int aPointIndex, int aNetcode ) thro
}
SEGVIA* SPECCTRA_DB::makeVIA( PADSTACK* aPadstack, const POINT& aPoint, int aNetCode )
{
SEGVIA* via = 0;
SHAPE* shape;
int shapeCount = aPadstack->Length();
int drillDiam = -1;
int viaDiam = 400;
// @todo this needs a lot of work yet, it is not complete yet.
// The drill diameter is encoded in the padstack name if PCBNEW did the DSN export.
// It is in mils and is after the colon and before the last '_'
int drillStartNdx = aPadstack->padstack_id.find( ':' );
if( drillStartNdx != -1 )
{
int drillEndNdx = aPadstack->padstack_id.rfind( '_' );
if( drillEndNdx != -1 )
{
std::string drillDiam( aPadstack->padstack_id, drillStartNdx, drillEndNdx-drillStartNdx-1 );
drillDiam = atoi( drillDiam.c_str() );
}
}
if( shapeCount == 0 )
{
}
else if( shapeCount == 1 )
{
shape = (SHAPE*) (*aPadstack)[0];
if( shape->shape->Type() == T_circle )
{
CIRCLE* circle = (CIRCLE*) shape->shape;
viaDiam = scale( circle->diameter, routeResolution );
via = new SEGVIA( sessionBoard );
via->SetPosition( mapPt( aPoint, routeResolution ) );
via->SetDrillValue( drillDiam );
via->m_Shape = VIA_THROUGH;
via->m_Width = viaDiam;
via->SetLayerPair( CMP_N, COPPER_LAYER_N );
}
}
else if( shapeCount == sessionBoard->GetCopperLayerCount() )
{
shape = (SHAPE*) (*aPadstack)[0];
if( shape->shape->Type() == T_circle )
{
CIRCLE* circle = (CIRCLE*) shape->shape;
viaDiam = scale( circle->diameter, routeResolution );
via = new SEGVIA( sessionBoard );
via->SetPosition( mapPt( aPoint, routeResolution ) );
via->SetDrillValue( drillDiam );
via->m_Shape = VIA_THROUGH;
via->m_Width = viaDiam;
via->SetLayerPair( CMP_N, COPPER_LAYER_N );
}
}
if( via )
via->SetNet( aNetCode );
return via;
}
// no UI code in this function, throw exception to report problems to the
// UI handler: void WinEDA_PcbFrame::ImportSpecctraSession( wxCommandEvent& event )
@ -268,15 +344,21 @@ void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) throw( IOError )
NET_OUTS& net_outs = session->route->net_outs;
for( NET_OUTS::iterator net=net_outs.begin(); net!=net_outs.end(); ++net )
{
wxString netName( CONV_FROM_UTF8( net->net_id.c_str() ) );
int netCode = 0;
// page 143 of spec says wire's net_id is optional
if( net->net_id.size() )
{
wxString netName = CONV_FROM_UTF8( net->net_id.c_str() );
EQUIPOT* equipot = aBoard->FindNet( netName );
if( !equipot )
{
ThrowIOError( _("Session file uses invalid net::net_id \"%s\""),
netName.GetData() );
if( equipot )
netCode = equipot->GetNet();
// else netCode remains 0
}
WIRES& wires = net->wires;
for( unsigned i=0; i<wires.size(); ++i )
{
@ -296,7 +378,7 @@ void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) throw( IOError )
PATH* path = (PATH*) wire->shape;
for( unsigned pt=0; pt<path->points.size()-1; ++pt )
{
TRACK* track = makeTRACK( path, pt, equipot->GetNet() );
TRACK* track = makeTRACK( path, pt, netCode );
TRACK* insertAid = track->GetBestInsertPoint( aBoard );
track->Insert( aBoard, insertAid );
@ -304,10 +386,48 @@ void SPECCTRA_DB::FromSESSION( BOARD* aBoard ) throw( IOError )
}
WIRE_VIAS& wire_vias = net->wire_vias;
LIBRARY& library = *session->route->library;
for( unsigned i=0; i<wire_vias.size(); ++i )
{
// WIRE_VIA* wire_via = &wire_vias[i];
int netCode = 0;
// page 144 of spec says wire_via's net_id is optional
if( net->net_id.size() )
{
wxString netName = CONV_FROM_UTF8( net->net_id.c_str() );
EQUIPOT* equipot = aBoard->FindNet( netName );
if( equipot )
netCode = equipot->GetNet();
// else netCode remains 0
}
WIRE_VIA* wire_via = &wire_vias[i];
// example: (via Via_15:8_mil 149000 -71000 )
PADSTACK* padstack = library.FindPADSTACK( wire_via->GetPadstackId() );
if( !padstack )
{
// Could use a STRINGFORMATTER here and convert the entire
// wire_via to text and put that text into the exception.
wxString psid( CONV_FROM_UTF8( wire_via->GetPadstackId().c_str() ) );
ThrowIOError( _("A wire_via references a missing padstack \"%s\""),
psid.GetData() );
}
for( unsigned v=0; v<wire_via->vertexes.size(); ++v )
{
SEGVIA* via = makeVIA( padstack, wire_via->vertexes[v], netCode );
if( !via )
ThrowIOError( _("Unable to make a via") );
TRACK* insertAid = via->GetBestInsertPoint( aBoard );
via->Insert( aBoard, insertAid );
}
}
}
}

View File

@ -24,23 +24,6 @@ referenced. I think this would be an easier way to manage xpms.
*** use BOARD_ITEM::MenuIcon() in the onrightclick.cpp
2007-Dec-4 Assigned To: Jean-Pierre, per his email
asked by: Dick Hollenbeck
================================================================================
1) Improve the zone support so that the perimeters of each zone are editable.
2) Allow zones to be added early in the routing process.
3) Remove the requirement to route tracks for situations where a zone is.
4) Support connections from zones to vias, and zones to tracks, and zones to pads.
rework zones so they are modifiable and so that the user does not
need to enter tracks for thru hole pads or vias which connect to a zone.
I propose a two step solution:
1) interim enhancement: make zone edges retained in BRD file and make the
edges editable.
2) final solution: get rid of requirement for tracks buried within a zone.
Reivew the GEDA source code and other sources to gather ideas before doing 2).
*** Use DOXYGEN compatible comments on member functions. As configured,
Doxygen gives priority to comments in header files over *.cpp files.
Review the generated docs and start to go through the source and make the
@ -56,7 +39,6 @@ understanding by new developers.
*** Add tooltip text to all non-obvious controls in every dialog window.
Need to do this using DialogBlocks.
2007-Nov-30 Assigned To: nobody
asked by: Dick Hollenbeck
================================================================================
@ -71,9 +53,27 @@ asked by: jp Charras
Use the collector classes in eeschema.
2008-Jan-25 Assigned To: any one who wants to
2008-Feb-8 Assigned To: dick
asked by: dick
================================================================================
Split the QARCs being created as 1/2 circles into quarter arcs. Problem
is in 4 places in specctra_export.cpp
specctra:
no blank pin numbers.
check that pin numbers are unique within a part, combine all such pins
into common padstack.
prompt for board boundary control, copper areas, tracks and vias, via per net, fixed vs. normal.
do write up.
2008-Feb-8 Assigned To: Jean-Pierre, per his email
asked by: Dick Hollenbeck
================================================================================
1) Remove the requirement to route tracks for situations where a zone is.
2) Support connections from zones to vias, and zones to tracks, and zones to pads.
rework zones so they are modifiable and so that the user does not
need to enter tracks for thru hole pads or vias which connect to a zone.
I propose a two step solution:
1) interim enhancement: make zone edges retained in BRD file and make the
edges editable.
2) final solution: get rid of requirement for tracks buried within a zone.
Reivew the GEDA source code and other sources to gather ideas before doing 2).