ADDED: Allow exporting IPC-356D netlists from Python
This commit is contained in:
parent
0049185d06
commit
ce4542cced
|
@ -44,28 +44,9 @@
|
|||
#include <vector>
|
||||
#include <cctype>
|
||||
#include <math/util.h> // for KiROUND
|
||||
#include <export_d356.h>
|
||||
|
||||
|
||||
/* Structure for holding the D-356 record fields.
|
||||
* Useful because 356A (when implemented) must be sorted before outputting it */
|
||||
struct D356_RECORD
|
||||
{
|
||||
bool smd;
|
||||
bool hole;
|
||||
wxString netname;
|
||||
wxString refdes;
|
||||
wxString pin;
|
||||
bool midpoint;
|
||||
int drill;
|
||||
bool mechanical;
|
||||
int access; // Access 0 is 'both sides'
|
||||
int soldermask;
|
||||
// All these in PCB units, will be output in decimils
|
||||
int x_location;
|
||||
int y_location;
|
||||
int x_size;
|
||||
int y_size;
|
||||
int rotation;
|
||||
};
|
||||
|
||||
// Compute the access code for a pad. Returns -1 if there is no copper
|
||||
static int compute_pad_access_code( BOARD *aPcb, LSET aLayerMask )
|
||||
|
@ -280,32 +261,32 @@ static const wxString intern_new_d356_netname( const wxString &aNetname,
|
|||
}
|
||||
|
||||
/* Write all the accumuled data to the file in D356 format */
|
||||
static void write_D356_records( std::vector <D356_RECORD> &aRecords,
|
||||
FILE *fout )
|
||||
void IPC356D_WRITER::write_D356_records( std::vector <D356_RECORD> &aRecords, FILE* aFile )
|
||||
{
|
||||
// Sanified and shorted network names and set of short names
|
||||
std::map<wxString, wxString> d356_net_map;
|
||||
std::set<wxString> d356_net_set;
|
||||
|
||||
for (unsigned i = 0; i < aRecords.size(); i++)
|
||||
for( unsigned i = 0; i < aRecords.size(); i++ )
|
||||
{
|
||||
D356_RECORD &rk = aRecords[i];
|
||||
|
||||
// Try to sanify the network name (there are limits on this), if
|
||||
// not already done. Also 'empty' net are marked as N/C, as
|
||||
// specified.
|
||||
wxString d356_net( wxT("N/C") );
|
||||
wxString d356_net( wxT( "N/C" ) );
|
||||
|
||||
if( !rk.netname.empty() )
|
||||
{
|
||||
d356_net = d356_net_map[rk.netname];
|
||||
|
||||
if( d356_net.empty() )
|
||||
d356_net = intern_new_d356_netname( rk.netname, d356_net_map,
|
||||
d356_net_set );
|
||||
d356_net = intern_new_d356_netname( rk.netname, d356_net_map, d356_net_set );
|
||||
}
|
||||
|
||||
// Choose the best record type
|
||||
int rktype;
|
||||
|
||||
if( rk.smd )
|
||||
rktype = 327;
|
||||
else
|
||||
|
@ -317,7 +298,7 @@ static void write_D356_records( std::vector <D356_RECORD> &aRecords,
|
|||
}
|
||||
|
||||
// Operation code, signal and component
|
||||
fprintf( fout, "%03d%-14.14s %-6.6s%c%-4.4s%c",
|
||||
fprintf( aFile, "%03d%-14.14s %-6.6s%c%-4.4s%c",
|
||||
rktype, TO_UTF8(d356_net),
|
||||
TO_UTF8(rk.refdes),
|
||||
rk.pin.empty()?' ':'-',
|
||||
|
@ -327,15 +308,15 @@ static void write_D356_records( std::vector <D356_RECORD> &aRecords,
|
|||
// Hole definition
|
||||
if( rk.hole )
|
||||
{
|
||||
fprintf( fout, "D%04d%c",
|
||||
fprintf( aFile, "D%04d%c",
|
||||
iu_to_d356( rk.drill, 9999 ),
|
||||
rk.mechanical ? 'U':'P' );
|
||||
}
|
||||
else
|
||||
fprintf( fout, " " );
|
||||
fprintf( aFile, " " );
|
||||
|
||||
// Test point access
|
||||
fprintf( fout, "A%02dX%+07dY%+07dX%04dY%04dR%03d",
|
||||
fprintf( aFile, "A%02dX%+07dY%+07dX%04dY%04dR%03d",
|
||||
rk.access,
|
||||
iu_to_d356( rk.x_location, 999999 ),
|
||||
iu_to_d356( rk.y_location, 999999 ),
|
||||
|
@ -344,16 +325,47 @@ static void write_D356_records( std::vector <D356_RECORD> &aRecords,
|
|||
rk.rotation );
|
||||
|
||||
// Soldermask
|
||||
fprintf( fout, "S%d\n", rk.soldermask );
|
||||
fprintf( aFile, "S%d\n", rk.soldermask );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IPC356D_WRITER::Write( const wxString& aFilename )
|
||||
{
|
||||
FILE* file = nullptr;
|
||||
LOCALE_IO toggle; // Switch the locale to standard C
|
||||
|
||||
if( ( file = wxFopen( aFilename, wxT( "wt" ) ) ) == nullptr )
|
||||
{
|
||||
wxString details;
|
||||
details.Printf( "The file %s could not be opened for writing", aFilename );
|
||||
DisplayErrorMessage( m_parent, "Could not write IPC-356D file!", details );
|
||||
return;
|
||||
}
|
||||
|
||||
// This will contain everything needed for the 356 file
|
||||
std::vector<D356_RECORD> d356_records;
|
||||
|
||||
build_via_testpoints( m_pcb, d356_records );
|
||||
|
||||
build_pad_testpoints( m_pcb, d356_records );
|
||||
|
||||
// Code 00 AFAIK is ASCII, CUST 0 is decimils/degrees
|
||||
// CUST 1 would be metric but gerbtool simply ignores it!
|
||||
fprintf( file, "P CODE 00\n" );
|
||||
fprintf( file, "P UNITS CUST 0\n" );
|
||||
fprintf( file, "P arrayDim N\n" );
|
||||
write_D356_records( d356_records, file );
|
||||
fprintf( file, "999\n" );
|
||||
|
||||
fclose( file );
|
||||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::GenD356File( wxCommandEvent& aEvent )
|
||||
{
|
||||
wxFileName fn = GetBoard()->GetFileName();
|
||||
wxString msg, ext, wildcard;
|
||||
FILE* file;
|
||||
|
||||
ext = IpcD356FileExtension;
|
||||
wildcard = IpcD356FileWildcard();
|
||||
|
@ -368,29 +380,7 @@ void PCB_EDIT_FRAME::GenD356File( wxCommandEvent& aEvent )
|
|||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
return;
|
||||
|
||||
if( ( file = wxFopen( dlg.GetPath(), wxT( "wt" ) ) ) == NULL )
|
||||
{
|
||||
msg = _( "Unable to create " ) + dlg.GetPath();
|
||||
DisplayError( this, msg ); return;
|
||||
}
|
||||
IPC356D_WRITER writer( GetBoard(), this );
|
||||
|
||||
LOCALE_IO toggle; // Switch the locale to standard C
|
||||
|
||||
// This will contain everything needed for the 356 file
|
||||
std::vector <D356_RECORD> d356_records;
|
||||
BOARD* pcb = GetBoard();
|
||||
|
||||
build_via_testpoints( pcb, d356_records );
|
||||
|
||||
build_pad_testpoints( pcb, d356_records );
|
||||
|
||||
// Code 00 AFAIK is ASCII, CUST 0 is decimils/degrees
|
||||
// CUST 1 would be metric but gerbtool simply ignores it!
|
||||
fprintf( file, "P CODE 00\n" );
|
||||
fprintf( file, "P UNITS CUST 0\n" );
|
||||
fprintf( file, "P arrayDim N\n" );
|
||||
write_D356_records( d356_records, file );
|
||||
fprintf( file, "999\n" );
|
||||
|
||||
fclose( file );
|
||||
writer.Write( dlg.GetPath() );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2020 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wx/string.h>
|
||||
|
||||
class BOARD;
|
||||
class wxWindow;
|
||||
|
||||
|
||||
/* Structure for holding the D-356 record fields.
|
||||
* Useful because 356A (when implemented) must be sorted before outputting it */
|
||||
struct D356_RECORD
|
||||
{
|
||||
bool smd;
|
||||
bool hole;
|
||||
wxString netname;
|
||||
wxString refdes;
|
||||
wxString pin;
|
||||
bool midpoint;
|
||||
int drill;
|
||||
bool mechanical;
|
||||
int access; // Access 0 is 'both sides'
|
||||
int soldermask;
|
||||
// All these in PCB units, will be output in decimils
|
||||
int x_location;
|
||||
int y_location;
|
||||
int x_size;
|
||||
int y_size;
|
||||
int rotation;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper to expose an API for writing IPC-D356 files
|
||||
*/
|
||||
class IPC356D_WRITER
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs an IPC-356D file writer
|
||||
* @param aPcb is the board to extract a netlist from
|
||||
* @param aParent will be used as the parent for any warning dialogs
|
||||
*/
|
||||
IPC356D_WRITER( BOARD* aPcb, wxWindow* aParent = nullptr ) :
|
||||
m_pcb( aPcb ), m_parent( aParent )
|
||||
{}
|
||||
|
||||
virtual ~IPC356D_WRITER() {}
|
||||
|
||||
/**
|
||||
* Generates and writes the netlist to a given path
|
||||
* @param aFilename is the full path and name of the output file
|
||||
*/
|
||||
void Write( const wxString& aFilename );
|
||||
|
||||
private:
|
||||
BOARD* m_pcb;
|
||||
|
||||
wxWindow* m_parent;
|
||||
|
||||
/// Writes a list of records to the given output stream
|
||||
void write_D356_records( std::vector<D356_RECORD> &aRecords, FILE* aFile );
|
||||
};
|
|
@ -70,6 +70,7 @@ class BASE_SET {};
|
|||
|
||||
#include <plotcontroller.h>
|
||||
#include <pcb_plot_params.h>
|
||||
#include <exporters/export_d356.h>
|
||||
#include <exporters/gendrill_file_writer_base.h>
|
||||
#include <exporters/gendrill_Excellon_writer.h>
|
||||
#include <exporters/gendrill_gerber_writer.h>
|
||||
|
@ -110,6 +111,7 @@ HANDLE_EXCEPTIONS(PLUGIN::FootprintDelete)
|
|||
%include <plotcontroller.h>
|
||||
%include <pcb_plot_params.h>
|
||||
%include <plotter.h>
|
||||
%include <exporters/export_d356.h>
|
||||
%include <exporters/gendrill_file_writer_base.h>
|
||||
%include <exporters/gendrill_Excellon_writer.h>
|
||||
%include <exporters/gendrill_gerber_writer.h>
|
||||
|
|
Loading…
Reference in New Issue