Gerbview: Added: read Excellon files created by Pcbnew. The full Excellon command set is not supported, but drill files created by Pcbnew are supported.
This commit is contained in:
parent
0d740e45e3
commit
ffbce6de84
|
@ -4,6 +4,12 @@ KiCad ChangeLog 2010
|
|||
Please add newer entries at the top, list the date and your name with
|
||||
email address.
|
||||
|
||||
2011-Mar-16, UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
|
||||
================================================================================
|
||||
Gerbview:
|
||||
Added: read Excellon files created by Pcbnew.
|
||||
The full Excellon command set is not supported, but drill files created by Pcbnew are supported.
|
||||
|
||||
2011-Feb-05, UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
|
||||
================================================================================
|
||||
CvPcb:
|
||||
|
|
|
@ -34,6 +34,7 @@ set(GERBVIEW_SRCS
|
|||
dummy_functions.cpp
|
||||
draw_gerber_screen.cpp
|
||||
events_called_functions.cpp
|
||||
excellon_read_drill_file.cpp
|
||||
export_to_pcbnew.cpp
|
||||
files.cpp
|
||||
gerbview.cpp
|
||||
|
|
|
@ -142,7 +142,16 @@ public:
|
|||
~GERBER_IMAGE();
|
||||
void Clear_GERBER_IMAGE();
|
||||
int ReturnUsedDcodeNumber();
|
||||
void ResetDefaultValues();
|
||||
virtual void ResetDefaultValues();
|
||||
|
||||
/**
|
||||
* Function GetParent
|
||||
* @return the GERBVIEW_FRAME parent of this GERBER_IMAGE
|
||||
*/
|
||||
GERBVIEW_FRAME* GetParent()
|
||||
{
|
||||
return m_Parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function GetLayerParams
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
/********************/
|
||||
/* class_excellon.h */
|
||||
/********************/
|
||||
|
||||
#ifndef CLASS_EXCELLON_H
|
||||
#define CLASS_EXCELLON_H
|
||||
|
||||
|
||||
enum drill_M_code_t {
|
||||
DRILL_M_UNKNOWN,
|
||||
DRILL_M_END,
|
||||
DRILL_M_ENDREWIND,
|
||||
DRILL_M_MESSAGE,
|
||||
DRILL_M_LONGMESSAGE,
|
||||
DRILL_M_HEADER,
|
||||
DRILL_M_ENDHEADER,
|
||||
DRILL_M_BEGINPATTERN,
|
||||
DRILL_M_ENDPATTERN,
|
||||
DRILL_M_CANNEDTEXT,
|
||||
DRILL_M_TIPCHECK,
|
||||
DRILL_M_METRIC,
|
||||
DRILL_M_IMPERIAL,
|
||||
DRILL_METRICHEADER,
|
||||
DRILL_IMPERIALHEADER,
|
||||
DRILL_DETECT_BROKEN,
|
||||
DRILL_INCREMENTALHEADER,
|
||||
DRILL_REWIND_STOP,
|
||||
DRILL_TOOL_CHANGE_STOP,
|
||||
DRILL_AUTOMATIC_SPEED,
|
||||
DRILL_AXIS_VERSION,
|
||||
DRILL_RESET_CMD,
|
||||
DRILL_AUTOMATIC_TOOL_CHANGE,
|
||||
DRILL_FMT,
|
||||
DRILL_SKIP,
|
||||
DRILL_TOOL_INFORMATION
|
||||
};
|
||||
|
||||
|
||||
enum drill_G_code_t {
|
||||
DRILL_G_UNKNOWN,
|
||||
DRILL_G_ABSOLUTE,
|
||||
DRILL_G_INCREMENTAL,
|
||||
DRILL_G_ZEROSET,
|
||||
DRILL_G_ROUT,
|
||||
DRILL_G_DRILL,
|
||||
DRILL_G_SLOT,
|
||||
DRILL_G_ZERO_SET,
|
||||
DRILL_G_LINEARMOVE,
|
||||
DRILL_G_CWMOVE,
|
||||
DRILL_G_CCWMOVE
|
||||
};
|
||||
|
||||
// Helper struct to analyse Excellon commands
|
||||
struct EXCELLON_CMD
|
||||
{
|
||||
string m_Name; // key string
|
||||
int m_Code; // internal code, used as id in functions
|
||||
int m_asParams; // 0 = no param, -1 = skip params, 1 = read params
|
||||
};
|
||||
|
||||
|
||||
/* EXCELLON_IMAGE handle a drill image
|
||||
* It is derived from GERBER_IMAGE because there is a lot of likeness
|
||||
* between EXCELLON files and GERBER files
|
||||
* DCode aperture are also similat to T Codes.
|
||||
* So we can reuse GERBER_IMAGE to handle EXCELLON_IMAGE with very few new functions
|
||||
*/
|
||||
|
||||
class EXCELLON_IMAGE : public GERBER_IMAGE
|
||||
{
|
||||
private:
|
||||
enum excellon_state {
|
||||
READ_HEADER_STATE, // When we are in this state, we are reading header
|
||||
READ_PROGRAM_STATE // When we are in this state, we are reading drill data
|
||||
};
|
||||
excellon_state m_State; // state of excellon file analysis
|
||||
bool m_SlotOn; // true during an oval driil definition
|
||||
|
||||
public: EXCELLON_IMAGE( GERBVIEW_FRAME* aParent, int layer ) :
|
||||
GERBER_IMAGE( aParent, layer )
|
||||
{
|
||||
m_State = READ_HEADER_STATE;
|
||||
m_SlotOn = false;
|
||||
}
|
||||
|
||||
|
||||
~EXCELLON_IMAGE() {};
|
||||
|
||||
virtual void ResetDefaultValues()
|
||||
{
|
||||
GERBER_IMAGE::ResetDefaultValues();
|
||||
SelectUnits( false );
|
||||
}
|
||||
|
||||
|
||||
bool Read_EXCELLON_File( FILE* aFile, const wxString& aFullFileName );
|
||||
|
||||
private:
|
||||
bool Execute_HEADER_Command( char*& text );
|
||||
bool Select_Tool( char*& text );
|
||||
bool Execute_EXCELLON_G_Command( char*& text );
|
||||
bool Execute_Drill_Command( char*& text );
|
||||
|
||||
int ReturnTCodeNumber( char*& Text )
|
||||
{
|
||||
return ReturnDCodeNumber( Text );
|
||||
}
|
||||
|
||||
|
||||
void SelectUnits( bool aMetric );
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* EXCELLON commands are given here.
|
||||
* Pcbnew uses only few excellon commands
|
||||
*/
|
||||
|
||||
/*
|
||||
* see http://www.excellon.com/manuals/program.htm
|
||||
*/
|
||||
|
||||
/* coordintes units:
|
||||
* Coordinates are measured either in inch or metric (millimeters).
|
||||
* Inch coordinates are in six digits (00.0000) with increments as small as 0.0001 (1/10,000).
|
||||
* Metric coordinates can be measured in microns (thousandths of a millimeter)
|
||||
* in one of the following three ways:
|
||||
* Five digit 10 micron resolution (000.00)
|
||||
* Six digit 10 micron resolution (0000.00)
|
||||
* Six digit micron resolution (000.000)
|
||||
*
|
||||
* Leading and trailing zeros:
|
||||
* Excellon (CNC-7) uses inches in six digits and metric in five or six digits.
|
||||
* The zeros to the left of the coordinate are called leading zeros (LZ).
|
||||
* The zeros to right of the coordinate are called trailing zeros (TZ).
|
||||
* The CNC-7 uses leading zeros unless you specify otherwise through a part program.
|
||||
* You can do so with the INCH/METRIC command.
|
||||
* With leading zeros, the leading zeros must always be included.
|
||||
* Trailing zeros are unneeded and may be left off.
|
||||
* For trailing zeros, the reverse of the above is true.
|
||||
*/
|
||||
|
||||
/*
|
||||
* EXCELLON Commands Used in a Header
|
||||
* The following table provides you with a list of commands which
|
||||
* are the most used in a part program header.
|
||||
* COMMAND DESCRIPTION
|
||||
* AFS Automatic Feeds and Speeds
|
||||
* ATC Automatic Tool Change
|
||||
* BLKD Delete all Blocks starting with a slash (/)
|
||||
* CCW Clockwise or Counter-clockwise Routing
|
||||
* CP Cutter Compensation
|
||||
* DETECT Broken Tool Detection
|
||||
* DN Down Limit Set
|
||||
* DTMDIST Maximum Rout Distance Before Toolchange
|
||||
* EXDA Extended Drill Area
|
||||
* FMAT Format 1 or 2
|
||||
* FSB Turns the Feed/Speed Buttons off
|
||||
* HPCK Home Pulse Check
|
||||
* ICI Incremental Input of Part Program Coordinates
|
||||
* INCH Measure Everything in Inches
|
||||
* METRIC Measure Everything in Metric
|
||||
* M48 Beginning of Part Program Header
|
||||
* M95 End of Header
|
||||
* NCSL NC Slope Enable/Disable
|
||||
* OM48 Override Part Program Header
|
||||
* OSTOP Optional Stop Switch
|
||||
* OTCLMP Override Table Clamp
|
||||
* PCKPARAM Set up pecking tool,depth,infeed and retract parameters
|
||||
* PF Floating Pressure Foot Switch
|
||||
* PPR Programmable Plunge Rate Enable
|
||||
* PVS Pre-vacuum Shut-off Switch
|
||||
* R,C Reset Clocks
|
||||
* R,CP Reset Program Clocks
|
||||
* R,CR Reset Run Clocks
|
||||
* R,D Reset All Cutter Distances
|
||||
* R,H Reset All Hit Counters
|
||||
* R,T Reset Tool Data
|
||||
* SBK Single Block Mode Switch
|
||||
* SG Spindle Group Mode
|
||||
* SIXM Input From External Source
|
||||
* T Tool Information
|
||||
* TCST Tool Change Stop
|
||||
* UP Upper Limit Set
|
||||
* VER Selection of X and Y Axis Version
|
||||
* Z Zero Set
|
||||
* ZA Auxiliary Zero
|
||||
* ZC Zero Correction
|
||||
* ZS Zero Preset
|
||||
* Z+# or Z-# Set Depth Offset
|
||||
* % Rewind Stop
|
||||
* #/#/# Link Tool for Automatic Tool Change
|
||||
* / Clear Tool Linking
|
||||
*/
|
||||
|
||||
/*
|
||||
* Beyond The Header: The Part Program Body
|
||||
* COMMAND DESCRIPTION
|
||||
* A# Arc Radius
|
||||
* B# Retract Rate
|
||||
* C# Tool Diameter
|
||||
* F# Table Feed Rate;Z Axis Infeed Rate
|
||||
* G00X#Y# Route Mode
|
||||
* G01 Linear (Straight Line) Mode
|
||||
* G02 Circular CW Mode
|
||||
* G03 Circular CCW Mode
|
||||
* G04 X# Variable Dwell
|
||||
* G05 Drill Mode
|
||||
* G07 Override current tool feed or speed
|
||||
* G32X#Y#A# Routed Circle Canned Cycle
|
||||
* CW G33X#Y#A# Routed Circle Canned Cycle
|
||||
* CCW G34,#(,#) Select Vision Tool
|
||||
* G35(X#Y#) Single Point Vision Offset (Relative to Work Zero)
|
||||
* G36(X#Y#) Multipoint Vision Translation (Relative to Work Zero)
|
||||
* G37 Cancel Vision Translation or Offset (From G35 or G36)
|
||||
* G38(X#Y#) Vision Corrected Single Hole Drilling (Relative to Work Zero)
|
||||
* G39(X#Y#) Vision System Autocalibration
|
||||
* G40 Cutter Compensation Off
|
||||
* G41 Cutter Compensation Left
|
||||
* G42 Cutter Compensation Right
|
||||
* G45(X#Y#) Single Point Vision Offset (Relative to G35 or G36)
|
||||
* G46(X#Y#) Multipoint Vision Translation (Relative to G35 or G36)
|
||||
* G47 Cancel Vision Translation or Offset (From G45 or G46)
|
||||
* G48(X#Y#) Vision Corrected Single Hole Drilling (Relative to G35 or G36)
|
||||
* G82(G81) Dual In Line Package
|
||||
* G83 Eight Pin L Pack
|
||||
* G84 Circle
|
||||
* G85 Slot
|
||||
* G87 Routed Step Slot Canned Cycle
|
||||
* G90 Absolute Mode
|
||||
* G91 Incremental Input Mode
|
||||
* G93X#Y# Zero Set
|
||||
* H# Maximum hit count
|
||||
* I#J# Arc Center Offset
|
||||
* M00(X#Y#) End of Program - No Rewind
|
||||
* M01 End of Pattern
|
||||
* M02X#Y# Repeat Pattern Offset
|
||||
* M06(X#Y#) Optional Stop
|
||||
* M08 End of Step and Repeat
|
||||
* M09(X#Y#) Stop for Inspection
|
||||
* M14 Z Axis Route Position With Depth Controlled Contouring
|
||||
* M15 Z Axis Route Position
|
||||
* M16 Retract With Clamping
|
||||
* M17 Retract Without Clamping
|
||||
* M18 Command tool tip check
|
||||
* M25 Beginning of Pattern
|
||||
* M30(X#Y#) End of Program Rewind
|
||||
* M45,long message\ Long Operator message on multiple\ part program lines
|
||||
* M47,text Operator Message
|
||||
* M50,# Vision Step and Repeat Pattern Start
|
||||
* M51,# Vision Step and Repeat Rewind
|
||||
* M52(#) Vision Step and Repeat Offset Counter Control
|
||||
* M02XYM70 Swap Axes
|
||||
* M60 Reference Scaling enable
|
||||
* M61 Reference Scaling disable
|
||||
* M62 Turn on peck drilling
|
||||
* M63 Turn off peck drilling
|
||||
* M71 Metric Measuring Mode
|
||||
* M72 Inch Measuring Mode
|
||||
* M02XYM80 Mirror Image X Axis
|
||||
* M02XYM90 Mirror Image Y Axis
|
||||
* M97,text Canned Text
|
||||
* M98,text Canned Text
|
||||
* M99,subprogram User Defined Stored Pattern
|
||||
* P#X#(Y#) Repeat Stored Pattern
|
||||
* R#M02X#Y# Repeat Pattern (S&R)
|
||||
* R#(X#Y#) Repeat Hole
|
||||
* S# Spindle RPM
|
||||
* T# Tool Selection; Cutter Index
|
||||
* Z+# or Z-# Depth Offset
|
||||
* % Beginning of Pattern (see M25 command)
|
||||
* / Block Delete
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example of a Header
|
||||
* COMMAND PURPOSE
|
||||
* M48 The beginning of a header
|
||||
* INCH,LZ Use the inch measuring system with leading zeros
|
||||
* VER,1 Use Version 1 X and Y axis layout
|
||||
* FMAT,2 Use Format 2 commands
|
||||
* 1/2/3 Link tools 1, 2, and 3
|
||||
* T1C.04F200S65 Set Tool 1 for 0.040" with infeed rate of 200 inch/min Speed of 65,000 RPM
|
||||
* DETECT,ON Detect broken tools
|
||||
* M95 End of the header
|
||||
*/
|
||||
|
||||
#endif // CLASS_EXCELLON_H
|
|
@ -0,0 +1,595 @@
|
|||
/********************************/
|
||||
/* excellon_read_drill_file.cpp */
|
||||
/********************************/
|
||||
|
||||
/*
|
||||
* Functions to read drill files (EXCELLON format) created by PcbNew
|
||||
* These files use only a subset of EXCELLON commands.
|
||||
* Here is a sample, in decimal format:
|
||||
* (Note: coordinates formats are same as Gerber, and T commands are near Gerber D commands).
|
||||
* M48
|
||||
* ;DRILL file {PCBnew (2011-03-14 BZR 2894)-testing} date 15/03/2011 14:23:22
|
||||
* ;FORMAT={-:-/ absolute / inch / decimal}
|
||||
* FMAT,2
|
||||
* INCH,TZ
|
||||
* T1C0.02
|
||||
* T2C0.032
|
||||
* %
|
||||
* G90
|
||||
* G05
|
||||
* M72
|
||||
* T1
|
||||
* X1.580Y-1.360
|
||||
* X1.580Y-4.860
|
||||
* X8.680Y-1.360
|
||||
* X8.680Y-4.860
|
||||
* T2
|
||||
* X2.930Y-3.560
|
||||
* X5.280Y-2.535
|
||||
* X5.405Y-2.610
|
||||
* X5.620Y-2.900
|
||||
* T0
|
||||
* M30
|
||||
*/
|
||||
#include "fctsys.h"
|
||||
#include "common.h"
|
||||
#include "confirm.h"
|
||||
|
||||
#include "gerbview.h"
|
||||
#include "trigo.h"
|
||||
#include "macros.h"
|
||||
#include "class_gerber_draw_item.h"
|
||||
#include "class_GERBER.h"
|
||||
#include "class_excellon.h"
|
||||
#include "kicad_string.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "dialog_load_error.h"
|
||||
|
||||
extern int ReadInt( char*& text, bool aSkipSeparator = true );
|
||||
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
|
||||
extern void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
APERTURE_T aAperture,
|
||||
int Dcode_index,
|
||||
int aLayer,
|
||||
const wxPoint& aPos,
|
||||
wxSize aSize,
|
||||
bool aLayerNegative );
|
||||
void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
int Dcode_index,
|
||||
int aLayer,
|
||||
const wxPoint& aStart,
|
||||
const wxPoint& aEnd,
|
||||
wxSize aPenSize,
|
||||
bool aLayerNegative );
|
||||
|
||||
static EXCELLON_CMD excellonHeaderCmdList[] =
|
||||
{
|
||||
{ "M0", DRILL_M_END, -1 }, // End of Program - No Rewind
|
||||
{ "M00", DRILL_M_END, -1 }, // End of Program - No Rewind
|
||||
{ "M30", DRILL_M_ENDREWIND, -1 }, // End of Program Rewind
|
||||
{ "M47", DRILL_M_MESSAGE, -1 }, // Operator Message
|
||||
{ "M45", DRILL_M_LONGMESSAGE, -1 }, // Long Operator message (use more than one line)
|
||||
{ "M48", DRILL_M_HEADER, 0 }, // beginning of a header
|
||||
{ "M95", DRILL_M_ENDHEADER, 0 }, // End of the header
|
||||
{ "METRIC", DRILL_METRICHEADER, 1 },
|
||||
{ "INCH", DRILL_IMPERIALHEADER, 1 },
|
||||
{ "M71", DRILL_M_METRIC, 1 },
|
||||
{ "M72", DRILL_M_IMPERIAL, 1 },
|
||||
{ "M25", DRILL_M_BEGINPATTERN, 0 }, // Beginning of Pattern
|
||||
{ "M01", DRILL_M_ENDPATTERN, 0 }, // End of Pattern
|
||||
{ "M97", DRILL_M_CANNEDTEXT, -1 },
|
||||
{ "M98", DRILL_M_CANNEDTEXT, -1 },
|
||||
{ "DETECT", DRILL_DETECT_BROKEN, -1 },
|
||||
{ "ICI", DRILL_INCREMENTALHEADER, 1 },
|
||||
{ "FMAT", DRILL_FMT, 1 }, // Use Format command
|
||||
{ "ATC", DRILL_AUTOMATIC_TOOL_CHANGE, 0 },
|
||||
{ "TCST", DRILL_TOOL_CHANGE_STOP, 0 }, // Tool Change Stop
|
||||
{ "AFS", DRILL_AUTOMATIC_SPEED }, // Automatic Feeds and Speeds
|
||||
{ "VER", DRILL_AXIS_VERSION, 1 }, // Selection of X and Y Axis Version
|
||||
{ "R", DRILL_RESET_CMD, -1 }, // Reset commands
|
||||
{ "%", DRILL_REWIND_STOP, -1 }, // Rewind stop. End of the header
|
||||
{ "/", DRILL_SKIP, -1 }, // Clear Tool Linking. End of the header
|
||||
// Keep this item after all commands starting by 'T':
|
||||
{ "T", DRILL_TOOL_INFORMATION, 0 }, // Tool Information
|
||||
{ "", DRILL_M_UNKNOWN, 0 } // last item in list
|
||||
};
|
||||
|
||||
static EXCELLON_CMD excellon_G_CmdList[] =
|
||||
{
|
||||
{ "G90", DRILL_G_ABSOLUTE, 0 }, // Absolute Mode
|
||||
{ "G91", DRILL_G_INCREMENTAL, 0 }, // Incremental Input Mode
|
||||
{ "G90", DRILL_G_ZEROSET, 0 }, // Absolute Mode
|
||||
{ "G00", DRILL_G_ROUT, 1 }, // Route Mode
|
||||
{ "G05", DRILL_G_DRILL, 0 }, // Drill Mode
|
||||
{ "G85", DRILL_G_SLOT, 0 }, // Drill Mode slot (oval holes)
|
||||
{ "G01", DRILL_G_LINEARMOVE, 0 }, // Linear (Straight Line) Mode
|
||||
{ "G02", DRILL_G_CWMOVE, 0 }, // Circular CW Mode
|
||||
{ "G03", DRILL_G_CCWMOVE, 0 }, // Circular CCW Mode
|
||||
{ "G93", DRILL_G_ZERO_SET, 1 }, // Zero Set (XnnYmm and coordintes origin)
|
||||
{ "", DRILL_G_UNKNOWN, 0 }, // last item in list
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Read a EXCELLON file.
|
||||
* Gerber classes are used because there is likeness between Gerber files
|
||||
* and Excellon files
|
||||
* DCode can easily store T code (tool size) as round (or oval) shape
|
||||
* Drill commands are similar to flashed gerber items
|
||||
* Routing commands are similar to Gerber polygons
|
||||
* coordinates have the same format as Gerber.
|
||||
*/
|
||||
bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
|
||||
{
|
||||
wxString msg;
|
||||
int layer = getActiveLayer(); // current layer used in gerbview
|
||||
|
||||
if( g_GERBER_List[layer] == NULL )
|
||||
{
|
||||
g_GERBER_List[layer] = new EXCELLON_IMAGE( this, layer );
|
||||
}
|
||||
|
||||
EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List[layer];
|
||||
ClearMessageList();
|
||||
|
||||
/* Read the gerber file */
|
||||
FILE * file = wxFopen( aFullFileName, wxT( "rt" ) );
|
||||
if( file == NULL )
|
||||
{
|
||||
msg.Printf( _( "File %s not found" ), GetChars( aFullFileName ) );
|
||||
DisplayError( this, msg, 10 );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString path = wxPathOnly( aFullFileName );
|
||||
if( path != wxEmptyString )
|
||||
wxSetWorkingDirectory( path );
|
||||
|
||||
bool success = drill_Layer->Read_EXCELLON_File( file, aFullFileName );
|
||||
|
||||
// Display errors list
|
||||
if( m_Messages.size() > 0 )
|
||||
{
|
||||
DIALOG_LOAD_ERROR dlg( this );
|
||||
dlg.ListSet( m_Messages );
|
||||
dlg.ShowModal();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile,
|
||||
const wxString & aFullFileName )
|
||||
{
|
||||
/* Set the gerber scale: */
|
||||
ResetDefaultValues();
|
||||
|
||||
m_FileName = aFullFileName;
|
||||
m_Current_File = aFile;
|
||||
|
||||
SetLocaleTo_C_standard();
|
||||
|
||||
// FILE_LINE_READER will close the file.
|
||||
if( m_Current_File == NULL )
|
||||
{
|
||||
wxMessageBox( wxT("NULL!"), m_FileName );
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE_LINE_READER excellonReader( m_Current_File, m_FileName );
|
||||
while( true )
|
||||
{
|
||||
if( excellonReader.ReadLine() == 0 )
|
||||
break;
|
||||
|
||||
char* line = excellonReader.Line();
|
||||
char* text = StrPurge( line );
|
||||
|
||||
if( *text == ';' ) // comment: skip line
|
||||
continue;
|
||||
|
||||
if( m_State == EXCELLON_IMAGE::READ_HEADER_STATE )
|
||||
{
|
||||
Execute_HEADER_Command( text );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( *text )
|
||||
{
|
||||
case 'M':
|
||||
Execute_HEADER_Command( text );
|
||||
break;
|
||||
|
||||
case 'G': /* Line type Gxx : command */
|
||||
Execute_EXCELLON_G_Command( text );
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
case 'Y': // command like X12550Y19250
|
||||
Execute_Drill_Command(text);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
case 'J': /* Auxiliary Move command */
|
||||
m_IJPos = ReadIJCoord( text );
|
||||
if( *text == '*' ) // command like X35142Y15945J504*
|
||||
{
|
||||
Execute_Drill_Command( text);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'T': // Tool command
|
||||
Select_Tool( text );
|
||||
break;
|
||||
|
||||
case '%':
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( wxT( "Unexpected symbol <%c>" ), *text );
|
||||
if( GetParent() )
|
||||
GetParent()->ReportMessage( msg );
|
||||
}
|
||||
break;
|
||||
} // End switch
|
||||
}
|
||||
}
|
||||
SetLocaleTo_Default();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EXCELLON_IMAGE::Execute_HEADER_Command( char*& text )
|
||||
{
|
||||
EXCELLON_CMD* cmd = NULL;
|
||||
int iprm;
|
||||
double dprm;
|
||||
D_CODE* dcode;
|
||||
wxString msg;
|
||||
|
||||
// Search command in list
|
||||
EXCELLON_CMD* candidate;
|
||||
|
||||
for( unsigned ii = 0; ; ii++ )
|
||||
{
|
||||
candidate = &excellonHeaderCmdList[ii];
|
||||
int len = candidate->m_Name.size();
|
||||
if( len == 0 ) // End of list reached
|
||||
break;
|
||||
if( candidate->m_Name.compare( 0, len, text, len ) == 0 ) // found.
|
||||
{
|
||||
cmd = candidate;
|
||||
text += len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !cmd )
|
||||
{
|
||||
msg.Printf( wxT( "Unknown Excellon command <%s>" ), text );
|
||||
ReportMessage( msg );
|
||||
while( *text )
|
||||
text++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Execute command
|
||||
// some do nothing
|
||||
switch( cmd->m_Code )
|
||||
{
|
||||
case DRILL_SKIP:
|
||||
case DRILL_M_UNKNOWN:
|
||||
break;
|
||||
|
||||
case DRILL_M_END:
|
||||
break;
|
||||
|
||||
case DRILL_M_ENDREWIND:
|
||||
break;
|
||||
|
||||
case DRILL_M_MESSAGE:
|
||||
break;
|
||||
|
||||
case DRILL_M_LONGMESSAGE:
|
||||
break;
|
||||
|
||||
case DRILL_M_HEADER:
|
||||
m_State = READ_HEADER_STATE;
|
||||
break;
|
||||
|
||||
case DRILL_M_ENDHEADER:
|
||||
m_State = READ_PROGRAM_STATE;
|
||||
break;
|
||||
|
||||
case DRILL_REWIND_STOP: // TODO: what this command really is ?
|
||||
m_State = READ_PROGRAM_STATE;
|
||||
break;
|
||||
|
||||
case DRILL_M_METRIC:
|
||||
SelectUnits( true );
|
||||
break;
|
||||
|
||||
case DRILL_METRICHEADER: // command like METRIC,TZ or METRIC,LZ
|
||||
SelectUnits( true );
|
||||
if( *text != ',' )
|
||||
{
|
||||
ReportMessage( _( "METRIC command has no parameter" ) );
|
||||
break;
|
||||
}
|
||||
text++; // skip separator
|
||||
if( *text == 'T' )
|
||||
m_NoTrailingZeros = false;
|
||||
else
|
||||
m_NoTrailingZeros = true;
|
||||
break;
|
||||
|
||||
case DRILL_M_IMPERIAL:
|
||||
SelectUnits( false );
|
||||
break;
|
||||
|
||||
case DRILL_IMPERIALHEADER: // command like INCH,TZ or INCH,LZ
|
||||
SelectUnits( false );
|
||||
if( *text != ',' )
|
||||
{
|
||||
ReportMessage( _( "INCH command has no parameter" ) );
|
||||
break;
|
||||
}
|
||||
text++; // skip separator
|
||||
if( *text == 'T' )
|
||||
m_NoTrailingZeros = false;
|
||||
else
|
||||
m_NoTrailingZeros = true;
|
||||
break;
|
||||
|
||||
case DRILL_M_BEGINPATTERN:
|
||||
break;
|
||||
|
||||
case DRILL_M_ENDPATTERN:
|
||||
break;
|
||||
|
||||
case DRILL_M_CANNEDTEXT:
|
||||
break;
|
||||
|
||||
case DRILL_M_TIPCHECK:
|
||||
break;
|
||||
|
||||
case DRILL_DETECT_BROKEN:
|
||||
break;
|
||||
|
||||
case DRILL_INCREMENTALHEADER:
|
||||
m_Relative = true;
|
||||
break;
|
||||
|
||||
case DRILL_TOOL_CHANGE_STOP:
|
||||
break;
|
||||
|
||||
case DRILL_AUTOMATIC_SPEED:
|
||||
break;
|
||||
|
||||
case DRILL_AXIS_VERSION:
|
||||
break;
|
||||
|
||||
case DRILL_RESET_CMD:
|
||||
break;
|
||||
|
||||
case DRILL_AUTOMATIC_TOOL_CHANGE:
|
||||
break;
|
||||
|
||||
case DRILL_FMT:
|
||||
break;
|
||||
|
||||
case DRILL_TOOL_INFORMATION:
|
||||
|
||||
// Read a tool definition like T1C0.02:
|
||||
// Read tool number:
|
||||
iprm = ReadInt( text, false );
|
||||
|
||||
// Read tool shape
|
||||
if( *text != 'C' )
|
||||
ReportMessage( _( "Tool definition <%c> not supported" ) );
|
||||
if( *text )
|
||||
text++;
|
||||
|
||||
//read tool diameter:
|
||||
dprm = ReadDouble( text, false );
|
||||
m_Has_DCode = true;
|
||||
|
||||
// Initialize Dcode to handle this Tool
|
||||
dcode = GetDCODE( iprm + FIRST_DCODE ); // Remember: dcodes are >= FIRST_DCODE
|
||||
if( dcode == NULL )
|
||||
break;
|
||||
double conv_scale = m_GerbMetric ? PCB_INTERNAL_UNIT / 25.4 : PCB_INTERNAL_UNIT;
|
||||
dcode->m_Size.x = dcode->m_Size.y = wxRound( dprm * conv_scale );
|
||||
dcode->m_Shape = APT_CIRCLE;
|
||||
break;
|
||||
}
|
||||
|
||||
while( *text )
|
||||
text++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EXCELLON_IMAGE::Execute_Drill_Command( char*& text )
|
||||
{
|
||||
D_CODE* tool;
|
||||
GERBER_DRAW_ITEM * gbritem;
|
||||
while( true )
|
||||
{
|
||||
switch( *text )
|
||||
{
|
||||
case 'X':
|
||||
ReadXYCoord( text );
|
||||
break;
|
||||
case 'Y':
|
||||
ReadXYCoord( text );
|
||||
break;
|
||||
case 'G': // G85 is found here for oval holes
|
||||
m_PreviousPos = m_CurrentPos;
|
||||
Execute_EXCELLON_G_Command( text );
|
||||
break;
|
||||
case 0: // E.O.L: execute command
|
||||
tool = GetDCODE( m_Current_Tool, false );
|
||||
if( !tool )
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Tool <%d> not defined" ), m_Current_Tool );
|
||||
ReportMessage( msg );
|
||||
return false;
|
||||
}
|
||||
gbritem = new GERBER_DRAW_ITEM( GetParent()->GetBoard(), this );
|
||||
GetParent()->GetBoard()->m_Drawings.Append( gbritem );
|
||||
if( m_SlotOn ) // Oval hole
|
||||
{
|
||||
fillLineGBRITEM( gbritem,
|
||||
tool->m_Num_Dcode, GetParent()->getActiveLayer(),
|
||||
m_PreviousPos, m_CurrentPos,
|
||||
tool->m_Size, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
fillFlashedGBRITEM( gbritem, tool->m_Shape,
|
||||
tool->m_Num_Dcode, GetParent()->getActiveLayer(),
|
||||
m_CurrentPos,
|
||||
tool->m_Size, false );
|
||||
}
|
||||
StepAndRepeatItem( *gbritem );
|
||||
m_PreviousPos = m_CurrentPos;
|
||||
return true;
|
||||
break;
|
||||
|
||||
default:
|
||||
text++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EXCELLON_IMAGE::Select_Tool( char*& text )
|
||||
{
|
||||
int tool_id = ReturnTCodeNumber( text );
|
||||
|
||||
if( tool_id >= 0 )
|
||||
{
|
||||
tool_id += FIRST_DCODE; // Remember: dcodes are >= FIRST_DCODE
|
||||
if( tool_id > (TOOLS_MAX_COUNT - 1) )
|
||||
tool_id = TOOLS_MAX_COUNT - 1;
|
||||
m_Current_Tool = tool_id;
|
||||
D_CODE* pt_Dcode = GetDCODE( tool_id , false );
|
||||
if( pt_Dcode )
|
||||
pt_Dcode->m_InUse = true;
|
||||
}
|
||||
while( *text )
|
||||
text++;
|
||||
|
||||
return tool_id >= 0;
|
||||
}
|
||||
|
||||
|
||||
bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
|
||||
{
|
||||
EXCELLON_CMD* cmd = NULL;
|
||||
bool success = false;
|
||||
int id = DRILL_G_UNKNOWN;
|
||||
|
||||
// Search command in list
|
||||
EXCELLON_CMD* candidate;
|
||||
char * gcmd = text; // gcmd points the G command, for error messages.
|
||||
|
||||
for( unsigned ii = 0; ; ii++ )
|
||||
{
|
||||
candidate = &excellon_G_CmdList[ii];
|
||||
int len = candidate->m_Name.size();
|
||||
if( len == 0 ) // End of list reached
|
||||
break;
|
||||
if( candidate->m_Name.compare( 0, len, text, len ) == 0 ) // found.
|
||||
{
|
||||
cmd = candidate;
|
||||
text += len;
|
||||
success = true;
|
||||
id = cmd->m_Code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch( id )
|
||||
{
|
||||
case DRILL_G_ZERO_SET:
|
||||
ReadXYCoord( text );
|
||||
m_Offset = m_CurrentPos;
|
||||
break;
|
||||
|
||||
case DRILL_G_ROUT:
|
||||
m_SlotOn = false;
|
||||
m_PolygonFillMode = true;
|
||||
break;
|
||||
|
||||
case DRILL_G_DRILL:
|
||||
m_SlotOn = false;
|
||||
m_PolygonFillMode = false;
|
||||
break;
|
||||
|
||||
case DRILL_G_SLOT:
|
||||
m_SlotOn = true;
|
||||
break;
|
||||
|
||||
case DRILL_G_LINEARMOVE:
|
||||
m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
|
||||
break;
|
||||
|
||||
case DRILL_G_CWMOVE:
|
||||
m_Iterpolation = GERB_INTERPOL_ARC_NEG;
|
||||
break;
|
||||
|
||||
case DRILL_G_CCWMOVE:
|
||||
m_Iterpolation = GERB_INTERPOL_ARC_POS;
|
||||
break;
|
||||
|
||||
case DRILL_G_ABSOLUTE:
|
||||
m_Relative = false; // false = absolute coord
|
||||
break;
|
||||
|
||||
case DRILL_G_INCREMENTAL:
|
||||
m_Relative = true; // true = relative coord
|
||||
break;
|
||||
|
||||
case DRILL_G_UNKNOWN:
|
||||
default:
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Unknown Excellon G Code: <%s>" ), GetChars(FROM_UTF8(gcmd)) );
|
||||
ReportMessage( msg );
|
||||
while( *text )
|
||||
text++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void EXCELLON_IMAGE::SelectUnits( bool aMetric )
|
||||
{
|
||||
/* Inches: Default fmt = 2.4 for X and Y axis: 6 digits with 0.0001 resolution (00.0000)
|
||||
* metric: Default fmt = 3.2 for X and Y axis: 5 digits, 1 micron resolution (00.000)
|
||||
*/
|
||||
if( aMetric )
|
||||
{
|
||||
m_GerbMetric = true;
|
||||
m_FmtScale.x = m_FmtScale.y = 3; // number of digits in mantissa: here 2
|
||||
m_FmtLen.x = m_FmtLen.y = 5; // number of digits: here 3+2
|
||||
}
|
||||
else
|
||||
{
|
||||
m_GerbMetric = false;
|
||||
m_FmtScale.x = m_FmtScale.y = 4; // number of digits in mantissa: here 4
|
||||
m_FmtLen.x = m_FmtLen.y = 6; // number of digits: here 2+4
|
||||
}
|
||||
}
|
|
@ -73,7 +73,8 @@ clear an existing layer to load any new layers." ), NB_LAYERS );
|
|||
break;
|
||||
|
||||
case ID_GERBVIEW_LOAD_DRILL_FILE:
|
||||
DisplayError( this, _( "Not yet available..." ) );
|
||||
LoadExcellonFiles( wxEmptyString );
|
||||
DrawPanel->Refresh();
|
||||
break;
|
||||
|
||||
case ID_GERBVIEW_LOAD_DCODE_FILE:
|
||||
|
@ -195,6 +196,88 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName )
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFullFileName )
|
||||
{
|
||||
wxString filetypes;
|
||||
wxArrayString filenamesList;
|
||||
wxFileName filename = aFullFileName;
|
||||
wxString currentPath;
|
||||
|
||||
if( !filename.IsOk() )
|
||||
{
|
||||
filetypes = _( "Drill files (.drl)" );
|
||||
filetypes << wxT("|");
|
||||
filetypes += wxT(";*.drl;*.DRL" );
|
||||
filetypes << wxT("|");
|
||||
/* All filetypes */
|
||||
filetypes += AllFilesWildcard;
|
||||
|
||||
/* Use the current working directory if the file name path does not exist. */
|
||||
if( filename.DirExists() )
|
||||
currentPath = filename.GetPath();
|
||||
else
|
||||
currentPath = wxGetCwd();
|
||||
|
||||
wxFileDialog dlg( this,
|
||||
_( "Open Drill File" ),
|
||||
currentPath,
|
||||
filename.GetFullName(),
|
||||
filetypes,
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE | wxFD_CHANGE_DIR );
|
||||
|
||||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
|
||||
dlg.GetPaths( filenamesList );
|
||||
currentPath = wxGetCwd();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFileName filename = aFullFileName;
|
||||
filenamesList.Add( aFullFileName );
|
||||
currentPath = filename.GetPath();
|
||||
}
|
||||
|
||||
// Read gerber files: each file is loaded on a new gerbview layer
|
||||
int layer = getActiveLayer();
|
||||
|
||||
for( unsigned ii = 0; ii < filenamesList.GetCount(); ii++ )
|
||||
{
|
||||
wxFileName filename = filenamesList[ii];
|
||||
|
||||
if( !filename.IsAbsolute() )
|
||||
filename.SetPath( currentPath );
|
||||
|
||||
GetScreen()->SetFileName( filename.GetFullPath() );
|
||||
|
||||
setActiveLayer( layer, false );
|
||||
|
||||
if( Read_EXCELLON_File( filename.GetFullPath() ) )
|
||||
{
|
||||
layer = getNextAvailableLayer( layer );
|
||||
|
||||
if( layer == NO_AVAILABLE_LAYERS )
|
||||
{
|
||||
wxString msg = wxT( "No more empty layers are available. The remaining gerber " );
|
||||
msg += wxT( "files will not be loaded." );
|
||||
wxMessageBox( msg );
|
||||
break;
|
||||
}
|
||||
|
||||
setActiveLayer( layer, false );
|
||||
}
|
||||
}
|
||||
|
||||
Zoom_Automatique( false );
|
||||
g_SaveTime = time( NULL );
|
||||
|
||||
// Synchronize layers tools with actual active layer:
|
||||
setActiveLayer( getActiveLayer() );
|
||||
syncLayerBox();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read a DCode file (not used with RX274X files , just with RS274D old files).
|
||||
|
|
|
@ -407,6 +407,17 @@ public: GERBVIEW_FRAME( wxWindow* father, const wxString& title,
|
|||
bool Read_GERBER_File( const wxString& GERBER_FullFileName,
|
||||
const wxString& D_Code_FullFileName );
|
||||
|
||||
/**
|
||||
* function LoadDrllFiles
|
||||
* Load a drill (EXCELLON) file or many files.
|
||||
* @param aFileName - void string or file name with full path to open or empty string to
|
||||
* open a new file. In this case one one file is loaded
|
||||
* if void string: user will be prompted for filename(s)
|
||||
* @return true if file was opened successfully.
|
||||
*/
|
||||
bool LoadExcellonFiles( const wxString& aFileName );
|
||||
bool Read_EXCELLON_File( const wxString& aFullFileName );
|
||||
|
||||
void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 );
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,10 +39,9 @@ void GERBVIEW_FRAME::ReCreateMenuBar( void )
|
|||
|
||||
filesMenu->Append( ID_GERBVIEW_LOAD_DCODE_FILE, _( "Load DCodes" ),
|
||||
_( "Load D-Codes File" ), FALSE );
|
||||
#if 0 // TODO
|
||||
|
||||
filesMenu->Append( ID_GERBVIEW_LOAD_DRILL_FILE, _( "Load EXCELLON Drill File" ),
|
||||
_( "Load excellon drill file" ), FALSE );
|
||||
#endif
|
||||
|
||||
filesMenu->Append( ID_NEW_BOARD, _( "&Clear All" ),
|
||||
_( "Clear all layers. All data will be deleted" ), FALSE );
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
* @param aSize The diameter of the round flash
|
||||
* @param aLayerNegative = true if the current layer is negative
|
||||
*/
|
||||
static void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
APERTURE_T aAperture,
|
||||
int Dcode_index,
|
||||
int aLayer,
|
||||
|
@ -138,7 +138,7 @@ static void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
|||
* @param aPenSize The size of the flash. Note rectangular shapes are legal.
|
||||
* @param aLayerNegative = true if the current layer is negative
|
||||
*/
|
||||
static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
int Dcode_index,
|
||||
int aLayer,
|
||||
const wxPoint& aStart,
|
||||
|
@ -725,10 +725,6 @@ bool GERBER_IMAGE::Execute_DCODE_Command( char*& text, int D_commande )
|
|||
|
||||
case 2: // code D2: exposure OFF (i.e. "move to")
|
||||
m_Exposure = false;
|
||||
|
||||
// D( printf( "Move to %d,%d to %d,%d\n",
|
||||
// m_PreviousPos.x, m_PreviousPos.y,
|
||||
// m_CurrentPos.x, m_CurrentPos.y ); )
|
||||
m_PreviousPos = m_CurrentPos;
|
||||
break;
|
||||
|
||||
|
@ -743,9 +739,6 @@ bool GERBER_IMAGE::Execute_DCODE_Command( char*& text, int D_commande )
|
|||
|
||||
gbritem = new GERBER_DRAW_ITEM( pcb, this );
|
||||
pcb->m_Drawings.Append( gbritem );
|
||||
|
||||
// D( printf( "Add flashed dcode %d layer %d at %d %d\n", dcode, activeLayer,
|
||||
// m_CurrentPos.x, m_CurrentPos.y ); )
|
||||
fillFlashedGBRITEM( gbritem, aperture,
|
||||
dcode, activeLayer, m_CurrentPos,
|
||||
size, GetLayerParams().m_LayerNegative );
|
||||
|
|
Loading…
Reference in New Issue