Pcbnew, Excellon drill file creation: for oval holes allows selection of an alternate command, when the normal command is not accepted.

Using the normal command, oval holes are "drilled" by a route command.
Some board houses do not accept this normal command.
In this case, the drill dialog allows using an other Excellon drill command (a slotted hole).
Note also some board houses do not understand this alternate command!
This commit is contained in:
jean-pierre charras 2019-02-09 14:56:02 +01:00
parent 756b20ace8
commit c0a86d734d
7 changed files with 264 additions and 795 deletions

View File

@ -5,8 +5,8 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 1992-2017 Jean_Pierre Charras <jp.charras at wanadoo.fr> * Copyright (C) 1992-2019 Jean_Pierre Charras <jp.charras at wanadoo.fr>
* Copyright (C) 1992-2017 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -47,7 +47,7 @@
#include <wx/stdpaths.h> #include <wx/stdpaths.h>
// Keywords for read and write config // Keywords for read and write parameters in project config
#define ZerosFormatKey wxT( "DrillZerosFormat" ) #define ZerosFormatKey wxT( "DrillZerosFormat" )
#define MirrorKey wxT( "DrillMirrorYOpt" ) #define MirrorKey wxT( "DrillMirrorYOpt" )
#define MinimalHeaderKey wxT( "DrillMinHeader" ) #define MinimalHeaderKey wxT( "DrillMinHeader" )
@ -55,10 +55,12 @@
#define UnitDrillInchKey wxT( "DrillUnit" ) #define UnitDrillInchKey wxT( "DrillUnit" )
#define DrillMapFileTypeKey wxT( "DrillMapFileType" ) #define DrillMapFileTypeKey wxT( "DrillMapFileType" )
#define DrillFileFormatKey wxT( "DrillFileType" ) #define DrillFileFormatKey wxT( "DrillFileType" )
#define OvalHolesRouteModeKey wxT( "OvalHolesRouteMode" )
// list of allowed precision for EXCELLON files, for integer format: // list of allowed precision for EXCELLON files, for integer format:
// Due to difference between inches and mm, // Due to difference between inches and mm,
// there are 2 precision values, one for inches and one for metric // there are 2 precision values, one for inches and one for metric
// Note: for decimla format, the precision is not used
static DRILL_PRECISION precisionListForInches( 2, 4 ); static DRILL_PRECISION precisionListForInches( 2, 4 );
static DRILL_PRECISION precisionListForMetric( 3, 3 ); static DRILL_PRECISION precisionListForMetric( 3, 3 );
@ -103,7 +105,7 @@ bool DIALOG_GENDRILL::m_Mirror = false; // Only for Excellon format
bool DIALOG_GENDRILL::m_Merge_PTH_NPTH = false; // Only for Excellon format bool DIALOG_GENDRILL::m_Merge_PTH_NPTH = false; // Only for Excellon format
int DIALOG_GENDRILL::m_mapFileType = 1; int DIALOG_GENDRILL::m_mapFileType = 1;
int DIALOG_GENDRILL::m_drillFileType = 0; int DIALOG_GENDRILL::m_drillFileType = 0;
bool DIALOG_GENDRILL::m_UseRouteModeForOvalHoles = true; // Use G00 route mode to "drill" oval holes
DIALOG_GENDRILL::~DIALOG_GENDRILL() DIALOG_GENDRILL::~DIALOG_GENDRILL()
{ {
@ -121,6 +123,7 @@ void DIALOG_GENDRILL::initDialog()
m_drillOriginIsAuxAxis = m_plotOpts.GetUseAuxOrigin(); m_drillOriginIsAuxAxis = m_plotOpts.GetUseAuxOrigin();
m_config->Read( DrillMapFileTypeKey, &m_mapFileType ); m_config->Read( DrillMapFileTypeKey, &m_mapFileType );
m_config->Read( DrillFileFormatKey, &m_drillFileType ); m_config->Read( DrillFileFormatKey, &m_drillFileType );
m_config->Read( OvalHolesRouteModeKey, &m_UseRouteModeForOvalHoles );
InitDisplayParams(); InitDisplayParams();
} }
@ -143,6 +146,7 @@ void DIALOG_GENDRILL::InitDisplayParams()
m_Check_Mirror->SetValue( m_Mirror ); m_Check_Mirror->SetValue( m_Mirror );
m_Check_Merge_PTH_NPTH->SetValue( m_Merge_PTH_NPTH ); m_Check_Merge_PTH_NPTH->SetValue( m_Merge_PTH_NPTH );
m_Choice_Drill_Map->SetSelection( m_mapFileType ); m_Choice_Drill_Map->SetSelection( m_mapFileType );
m_radioBoxOvalHoleMode->SetSelection( m_UseRouteModeForOvalHoles ? 0 : 1 );
m_platedPadsHoleCount = 0; m_platedPadsHoleCount = 0;
m_notplatedPadsHoleCount = 0; m_notplatedPadsHoleCount = 0;
@ -228,6 +232,7 @@ void DIALOG_GENDRILL::onFileFormatSelection( wxCommandEvent& event )
m_Check_Mirror->Enable( enbl_Excellon ); m_Check_Mirror->Enable( enbl_Excellon );
m_Check_Minimal->Enable( enbl_Excellon ); m_Check_Minimal->Enable( enbl_Excellon );
m_Check_Merge_PTH_NPTH->Enable( enbl_Excellon ); m_Check_Merge_PTH_NPTH->Enable( enbl_Excellon );
m_radioBoxOvalHoleMode->Enable( enbl_Excellon );
if( enbl_Excellon ) if( enbl_Excellon )
UpdatePrecisionOptions(); UpdatePrecisionOptions();
@ -250,6 +255,7 @@ void DIALOG_GENDRILL::UpdateConfig()
m_config->Write( UnitDrillInchKey, m_UnitDrillIsInch ); m_config->Write( UnitDrillInchKey, m_UnitDrillIsInch );
m_config->Write( DrillMapFileTypeKey, m_mapFileType ); m_config->Write( DrillMapFileTypeKey, m_mapFileType );
m_config->Write( DrillFileFormatKey, m_drillFileType ); m_config->Write( DrillFileFormatKey, m_drillFileType );
m_config->Write( OvalHolesRouteModeKey, m_UseRouteModeForOvalHoles );
} }
@ -346,6 +352,7 @@ void DIALOG_GENDRILL::SetParams()
m_Mirror = m_Check_Mirror->IsChecked(); m_Mirror = m_Check_Mirror->IsChecked();
m_Merge_PTH_NPTH = m_Check_Merge_PTH_NPTH->IsChecked(); m_Merge_PTH_NPTH = m_Check_Merge_PTH_NPTH->IsChecked();
m_ZerosFormat = m_Choice_Zeros_Format->GetSelection(); m_ZerosFormat = m_Choice_Zeros_Format->GetSelection();
m_UseRouteModeForOvalHoles = m_radioBoxOvalHoleMode->GetSelection() == 0;
if( m_Choice_Drill_Offset->GetSelection() == 0 ) if( m_Choice_Drill_Offset->GetSelection() == 0 )
m_FileDrillOffset = wxPoint( 0, 0 ); m_FileDrillOffset = wxPoint( 0, 0 );
@ -399,6 +406,7 @@ void DIALOG_GENDRILL::GenDrillAndMapFiles( bool aGenDrill, bool aGenMap )
excellonWriter.SetFormat( !m_UnitDrillIsInch, (EXCELLON_WRITER::ZEROS_FMT) m_ZerosFormat, excellonWriter.SetFormat( !m_UnitDrillIsInch, (EXCELLON_WRITER::ZEROS_FMT) m_ZerosFormat,
m_Precision.m_lhs, m_Precision.m_rhs ); m_Precision.m_lhs, m_Precision.m_rhs );
excellonWriter.SetOptions( m_Mirror, m_MinimalHeader, m_FileDrillOffset, m_Merge_PTH_NPTH ); excellonWriter.SetOptions( m_Mirror, m_MinimalHeader, m_FileDrillOffset, m_Merge_PTH_NPTH );
excellonWriter.SetRouteModeForOvalHoles( m_UseRouteModeForOvalHoles );
excellonWriter.SetMapFileFormat( filefmt[choice] ); excellonWriter.SetMapFileFormat( filefmt[choice] );
excellonWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(), excellonWriter.CreateDrillandMapFilesSet( outputDir.GetFullPath(),

View File

@ -5,8 +5,8 @@
/* /*
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 1992-2010 Jean_Pierre Charras <jp.charras@ujf-grenoble.fr> * Copyright (C) 1992-2019 Jean_Pierre Charras <jp.charras@ujf-grenoble.fr>
* Copyright (C) 1992-2010 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -42,9 +42,11 @@ public:
static bool m_MinimalHeader; static bool m_MinimalHeader;
static bool m_Mirror; static bool m_Mirror;
static bool m_Merge_PTH_NPTH; static bool m_Merge_PTH_NPTH;
DRILL_PRECISION m_Precision; // Selected precision for drill files DRILL_PRECISION m_Precision; /// Selected precision for drill files, in non decimal format
wxPoint m_FileDrillOffset; // Drill offset: 0,0 for absolute coordinates, wxPoint m_FileDrillOffset; /// Drill offset: 0,0 for absolute coordinates,
// or origin of the auxiliary axis /// or origin of the auxiliary axis
static bool m_UseRouteModeForOvalHoles; /// True to use a G00 route command for oval holes
/// False to use a G85 canned mode for oval holes
private: private:
@ -52,16 +54,16 @@ private:
wxConfigBase* m_config; wxConfigBase* m_config;
BOARD* m_board; BOARD* m_board;
PCB_PLOT_PARAMS m_plotOpts; PCB_PLOT_PARAMS m_plotOpts;
bool m_drillOriginIsAuxAxis; // Axis selection (main / auxiliary) bool m_drillOriginIsAuxAxis; // Axis selection (main / auxiliary)
// for drill origin coordinates // for drill origin coordinates
int m_platedPadsHoleCount; int m_platedPadsHoleCount;
int m_notplatedPadsHoleCount; int m_notplatedPadsHoleCount;
int m_throughViasCount; int m_throughViasCount;
int m_microViasCount; int m_microViasCount;
int m_blindOrBuriedViasCount; int m_blindOrBuriedViasCount;
static int m_mapFileType; // HPGL, PS ... static int m_mapFileType; // format of map file: HPGL, PS ...
static int m_drillFileType; // Excellon, Gerber static int m_drillFileType; // for Excellon, Gerber
void initDialog(); void initDialog();

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Dec 30 2017) // C++ code generated with wxFormBuilder (version Dec 1 2018)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -28,7 +28,7 @@ DIALOG_GENDRILL_BASE::DIALOG_GENDRILL_BASE( wxWindow* parent, wxWindowID id, con
bupperSizer->Add( m_outputDirectoryName, 1, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 0 ); bupperSizer->Add( m_outputDirectoryName, 1, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT|wxTOP, 0 );
m_browseButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); m_browseButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW|0 );
m_browseButton->SetMinSize( wxSize( 30,28 ) ); m_browseButton->SetMinSize( wxSize( 30,28 ) );
bupperSizer->Add( m_browseButton, 0, wxRIGHT, 7 ); bupperSizer->Add( m_browseButton, 0, wxRIGHT, 7 );
@ -64,7 +64,15 @@ DIALOG_GENDRILL_BASE::DIALOG_GENDRILL_BASE( wxWindow* parent, wxWindowID id, con
m_Check_Merge_PTH_NPTH = new wxCheckBox( sbSizer6->GetStaticBox(), wxID_ANY, _("PTH and NPTH in single file"), wxDefaultPosition, wxDefaultSize, 0 ); m_Check_Merge_PTH_NPTH = new wxCheckBox( sbSizer6->GetStaticBox(), wxID_ANY, _("PTH and NPTH in single file"), wxDefaultPosition, wxDefaultSize, 0 );
m_Check_Merge_PTH_NPTH->SetToolTip( _("Not recommended.\nOnly use for board houses which ask for merged PTH and NPTH into a single file.") ); m_Check_Merge_PTH_NPTH->SetToolTip( _("Not recommended.\nOnly use for board houses which ask for merged PTH and NPTH into a single file.") );
bSizerExcellonOptions->Add( m_Check_Merge_PTH_NPTH, 0, wxBOTTOM|wxLEFT, 5 ); bSizerExcellonOptions->Add( m_Check_Merge_PTH_NPTH, 0, wxLEFT, 5 );
wxString m_radioBoxOvalHoleModeChoices[] = { _("Use route command (recommended)"), _("Use alternate drill mode") };
int m_radioBoxOvalHoleModeNChoices = sizeof( m_radioBoxOvalHoleModeChoices ) / sizeof( wxString );
m_radioBoxOvalHoleMode = new wxRadioBox( sbSizer6->GetStaticBox(), wxID_ANY, _("Oval Holes Drill Mode"), wxDefaultPosition, wxDefaultSize, m_radioBoxOvalHoleModeNChoices, m_radioBoxOvalHoleModeChoices, 1, wxRA_SPECIFY_COLS );
m_radioBoxOvalHoleMode->SetSelection( 0 );
m_radioBoxOvalHoleMode->SetToolTip( _("Oval holes frequently create problems for board houses.\n\"Use route command\" uses the usual G00 route command (recommended)\n \"Use alternate mode\" uses another drill/ route command (G85)\n(Use it only if the recommended command does not work)") );
bSizerExcellonOptions->Add( m_radioBoxOvalHoleMode, 0, wxALL|wxEXPAND, 5 );
sbSizer6->Add( bSizerExcellonOptions, 1, wxEXPAND|wxLEFT, 12 ); sbSizer6->Add( bSizerExcellonOptions, 1, wxEXPAND|wxLEFT, 12 );
@ -227,7 +235,6 @@ DIALOG_GENDRILL_BASE::DIALOG_GENDRILL_BASE( wxWindow* parent, wxWindowID id, con
this->SetSizer( bMainSizer ); this->SetSizer( bMainSizer );
this->Layout(); this->Layout();
bMainSizer->Fit( this );
this->Centre( wxBOTH ); this->Centre( wxBOTH );

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,11 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Dec 30 2017) // C++ code generated with wxFormBuilder (version Dec 1 2018)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_GENDRILL_BASE_H__ #pragma once
#define __DIALOG_GENDRILL_BASE_H__
#include <wx/artprov.h> #include <wx/artprov.h>
#include <wx/xrc/xmlres.h> #include <wx/xrc/xmlres.h>
@ -19,16 +18,16 @@
#include <wx/colour.h> #include <wx/colour.h>
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h> #include <wx/bitmap.h>
#include <wx/image.h> #include <wx/image.h>
#include <wx/icon.h> #include <wx/icon.h>
#include <wx/bmpbuttn.h>
#include <wx/button.h> #include <wx/button.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/radiobut.h> #include <wx/radiobut.h>
#include <wx/checkbox.h> #include <wx/checkbox.h>
#include <wx/statbox.h>
#include <wx/radiobox.h> #include <wx/radiobox.h>
#include <wx/statbox.h>
#include <wx/dialog.h> #include <wx/dialog.h>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -49,6 +48,7 @@ class DIALOG_GENDRILL_BASE : public DIALOG_SHIM
wxCheckBox* m_Check_Mirror; wxCheckBox* m_Check_Mirror;
wxCheckBox* m_Check_Minimal; wxCheckBox* m_Check_Minimal;
wxCheckBox* m_Check_Merge_PTH_NPTH; wxCheckBox* m_Check_Merge_PTH_NPTH;
wxRadioBox* m_radioBoxOvalHoleMode;
wxRadioButton* m_rbGerberX2; wxRadioButton* m_rbGerberX2;
wxRadioBox* m_Choice_Drill_Map; wxRadioBox* m_Choice_Drill_Map;
wxRadioBox* m_Choice_Drill_Offset; wxRadioBox* m_Choice_Drill_Offset;
@ -86,9 +86,8 @@ class DIALOG_GENDRILL_BASE : public DIALOG_SHIM
public: public:
DIALOG_GENDRILL_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Generate Drill Files"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); DIALOG_GENDRILL_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Generate Drill Files"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 568,514 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_GENDRILL_BASE(); ~DIALOG_GENDRILL_BASE();
}; };
#endif //__DIALOG_GENDRILL_BASE_H__

View File

@ -58,9 +58,9 @@
// Oblong holes can be drilled by a "canned slot" command (G85) or a routing command // Oblong holes can be drilled by a "canned slot" command (G85) or a routing command
// a linear routing command (G01) is perhaps more usual for drill files // a linear routing command (G01) is perhaps more usual for drill files
// Comment this next line to use a canned slot hole (old way) //
// Uncomment this next line to use a linear routed hole (new way) // set m_useRouteModeForOval to false to use a canned slot hole (old way)
#define USE_ROUTING_MODE_FOR_OBLONG_HOLE // set m_useRouteModeForOval to true (prefered mode) to use a linear routed hole (new way)
EXCELLON_WRITER::EXCELLON_WRITER( BOARD* aPcb ) EXCELLON_WRITER::EXCELLON_WRITER( BOARD* aPcb )
: GENDRILL_WRITER_BASE( aPcb ) : GENDRILL_WRITER_BASE( aPcb )
@ -72,6 +72,7 @@ EXCELLON_WRITER::EXCELLON_WRITER( BOARD* aPcb )
m_merge_PTH_NPTH = false; m_merge_PTH_NPTH = false;
m_minimalHeader = false; m_minimalHeader = false;
m_drillFileExtension = DrillFileExtension; m_drillFileExtension = DrillFileExtension;
m_useRouteModeForOval = true;
} }
@ -272,35 +273,41 @@ int EXCELLON_WRITER::createDrillFile( FILE* aFile, DRILL_LAYER_PAIR aLayerPair,
xt = x0 * m_conversionUnits; xt = x0 * m_conversionUnits;
yt = y0 * m_conversionUnits; yt = y0 * m_conversionUnits;
#ifdef USE_ROUTING_MODE_FOR_OBLONG_HOLE
fputs( "G00", m_file ); // Select the routing mode if( m_useRouteModeForOval )
#endif fputs( "G00", m_file ); // Select the routing mode
writeCoordinates( line, xt, yt ); writeCoordinates( line, xt, yt );
#ifndef USE_ROUTING_MODE_FOR_OBLONG_HOLE if( !m_useRouteModeForOval )
/* remove the '\n' from end of line, because we must add the "G85"
* command to the line: */
for( int kk = 0; line[kk] != 0; kk++ )
{ {
if( line[kk] < ' ' ) /* remove the '\n' from end of line, because we must add the "G85"
line[kk] = 0; * command to the line: */
for( int kk = 0; line[kk] != 0; kk++ )
{
if( line[kk] < ' ' )
line[kk] = 0;
}
fputs( line, m_file );
fputs( "G85", m_file ); // add the "G85" command
}
else
{
fputs( line, m_file );
fputs( "M15\nG01", m_file ); // tool down and linear routing from last coordinates
} }
fputs( line, m_file );
fputs( "G85", m_file ); // add the "G85" command
#else
fputs( line, m_file );
fputs( "M15\nG01", m_file ); // tool down and linear routing from last coordinates
#endif
xt = xf * m_conversionUnits; xt = xf * m_conversionUnits;
yt = yf * m_conversionUnits; yt = yf * m_conversionUnits;
writeCoordinates( line, xt, yt ); writeCoordinates( line, xt, yt );
fputs( line, m_file ); fputs( line, m_file );
#ifdef USE_ROUTING_MODE_FOR_OBLONG_HOLE
fputs( "M16\n", m_file ); // Tool up (end routing) if( m_useRouteModeForOval )
#endif fputs( "M16\n", m_file ); // Tool up (end routing)
fputs( "G05\n", m_file ); // Select drill mode
fputs( "G05\n", m_file ); // Select drill mode
holes_count++; holes_count++;
} }

View File

@ -44,9 +44,12 @@ class OUTPUTFORMATTER;
class EXCELLON_WRITER: public GENDRILL_WRITER_BASE class EXCELLON_WRITER: public GENDRILL_WRITER_BASE
{ {
private: private:
FILE* m_file; // The output file FILE* m_file; // The output file
bool m_minimalHeader; // True to use minimal header bool m_minimalHeader; // True to use minimal header
bool m_mirror; bool m_mirror;
bool m_useRouteModeForOval; // True to use a route command for oval holes
// False to use a G85 canned mode for oval holes
public: public:
EXCELLON_WRITER( BOARD* aPcb ); EXCELLON_WRITER( BOARD* aPcb );
@ -61,6 +64,14 @@ public:
*/ */
const wxPoint GetOffset() { return m_offset; } const wxPoint GetOffset() { return m_offset; }
/**
*
*/
void SetRouteModeForOvalHoles( bool aUseRouteModeForOvalHoles )
{
m_useRouteModeForOval = aUseRouteModeForOvalHoles;
}
/** /**
* Function SetFormat * Function SetFormat
* Initialize internal parameters to match the given format * Initialize internal parameters to match the given format