//
// Generate g-code for milling PC boards.
//
// Copyright 2004-2013 by John Johnson Software, LLC.
// See readme.html for copyright information.
//
// See pcb-defaults.h, gcode-defaults.h and pcb-machine.h for options.
//
#include "source/pcb-gcode.h"
#include "source/pcb-gcode-stack.h"
#include "settings/pcb-defaults.h"
#include "settings/pcb-machine.h"
#include "settings/gcode-defaults.h"
#include "settings/pcb-gcode-options.h"
#include "settings/user-gcode.h"
#include "source/math.h"
#include "source/drill.h"
#include "source/library.h"
#include "source/pcb-file-utils.h"
#include "source/filename_subs.h"
#usage "
pcb-gcode™ Gcode Generation Utility
"
" Version 3.6.0.4"
"Copyright© 2004 - 2013 by John Johnson Software, LLC
"
"All Rights Reserved
"
""
"Join the Yahoo! pcb-gcode group "
"http://groups.yahoo.com/group/pcb-gcode"
"
or contact the author at pcbgcode@pcbgcode.org"
"
"
"
"
"This program generates g-code for 'mechanically etching' PC boards. "
"Using a CNC router or milling machine, you can make PC boards without using etching chemicals."
"It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board."
"
See the readme.html file for more info."
"There are many options in the setup program.
"
"To setup which files are generated, and how, use the following command:
"
"run pcb-gcode --setup
"
"
"
"If you want to produce a set of files without changing options, you can run pcb-gcode directly."
"Usage is as follows:
"
"run pcb-gcode [option] [file]
"
"Where:\n"
""
"| Option | Function |
"
"--help | Show this help screen |
"
"--setup | Run the setup / configuration program |
"
"file | Is the optional root filename.\n |
"
" | If not given, the board name is used as the root filename. |
"
"
"
""
""
"
"
g_width = DEFAULT_WIDTH;
// Filename to output to.
string m_file_name = "";
// Which side we're currently working on.
g_side = TOP;
// Tool currently being used.
int m_current_tool = 0;
// Amount to isolate traces.
real m_isolate = 0.0;
// Used to pass the pass info to the next pass of the program.
int m_pass_num;
// The layer being worked on.
int m_layer;
// Used to create command strings.
string g_cmd;
string g_cmd_temp;
// Save the maximum and minimum coordinates.
real m_max_x;
real m_max_y;
real m_min_x;
real m_min_y;
void save_extents(real x, real y)
{
m_max_x = max(m_max_x, x);
m_max_y = max(m_max_y, y);
m_min_x = min(m_min_x, x);
m_min_y = min(m_min_y, y);
}
void preview()
{
if (SHOW_PREVIEW) {
switch(get_os()) {
case OS_MACOSX:
system(g_path + "/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub");
break;
case OS_LINUX:
system(g_path + "/source/viewer.linux.sh");
break;
case OS_WINDOWS:
system(g_path + "/viewer/application.windows/viewer.exe");
dlgMessageBox("Close this window when you have finished with the preview");
break;
default:
Fatal("Oops!", "Can't figure out which OS you have.");
}
}
}
//
// Determine the next phase, and set g_phase accordingly.
//
// Params: none
// Return: none
//
void next_phase(void)
{
if (g_phase == PH_TOP_OUT_GEN && GENERATE_TOP_OUTLINES != YES) {
g_phase += 2;
return;
}
if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) {
g_phase += 2;
return;
}
if (g_phase == PH_TOP_OUT_WRITE || g_phase == PH_BOTTOM_OUT_WRITE) {
if (m_isolate < ISO_MAX && !SINGLE_PASS) {
m_isolate += ISO_STEP;
m_pass_num++;
g_phase--;
}
else {
m_isolate = ISO_MIN;
m_pass_num = 0;
g_phase++;
preview();
}
}
else {
g_phase++;
}
}
//////////////////////////////////////////////////
//
// Hole drilling routines.
//
//////////////////////////////////////////////////
//
// Add a hole drilling command to the command string.
//
// Params:
// Size Drill size.
// x x coordinate.
// y y coordinate.
// Returns:
// none
// Changes:
// the stack
//
void add_hole(int req_size, int x, int y)
{
string tempstr;
int drill_size;
drill_size = get_drill_for(req_size);
sprintf(tempstr, "%06d\t%06d\t%06d", drill_size, x, y);
stack_push(tempstr);
}
/*
* Create a drill file for the desired side.
*
* Params:
* which_side Side to produce the file for.
* suffix Suffix to use for the file name (i.e. bd).
* Returns:
* none
* Changes:
* side
*/
void drill(int which_side, string suffix)
{
int num_lines;
int i;
real last_size;
string drill_args[];
m_current_tool = 0;
real drill_size_mm;
real drill_size_inch;
real drill_size;
real drill_x;
real drill_y;
int drill_tool_num;
g_side = which_side;
//
// Build a stack with all the holes.
//
board(B) {
B.holes(H) add_hole(H.drill, H.x, H.y);
B.signals(S) S.vias(V) add_hole(V.drill, V.x, V.y);
B.elements(E) {
E.package.contacts(C) {
if (C.pad) {
add_hole(C.pad.drill, C.pad.x, C.pad.y);
}
}
E.package.holes(H) add_hole(H.drill, H.x, H.y);
}
// B.elements
// Sorts the drills by size, x and y.
stack_sort();
//
// Create the drill g-code file.
//
last_size = -1;
output(get_filename(), "wt") {
output_file_preamble();
//
// Create a tool table at the beginning of the file.
//
out(TOOL_CHANGE_TABLE_HEADER);
for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
if (i==END_OF_STACK) break;
strsplit(drill_args, stack_elem(i), '\t');
drill_size_inch = u2inch(my_strtol(drill_args[DRILL_SIZE]));
drill_size_mm = u2mm(my_strtol(drill_args[DRILL_SIZE]));
drill_size = my_strtol(drill_args[DRILL_SIZE]);
if (drill_size != last_size) {
++m_current_tool;
drill_tool_num = get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool);
out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num,
drill_size_mm, drill_size_inch,
g_mins[drill_tool_num], g_maxs[drill_tool_num],
g_drill_sub_cnt[drill_tool_num]));
}
last_size = drill_size;
}
// for
// Set the mode for the user's UOM.
out(get_mode());
out(ABSOLUTE_MODE);
//
// Generate drill code.
//
m_current_tool = 0;
for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) {
strsplit(drill_args, stack_elem(i), '\t');
drill_size = units(my_strtol(drill_args[DRILL_SIZE]));
drill_x = scale_x(my_strtol(drill_args[DRILL_X]));
drill_y = scale_y(my_strtol(drill_args[DRILL_Y]));
save_extents(drill_x, drill_y);
if (drill_size == last_size) {
output_drill_hole(drill_x, drill_y, DRILL_DEPTH);
}
else {
m_current_tool++;
// Tool change routine
output_tool_change_begin();
out(SPINDLE_OFF);
rz(TOOL_CHANGE_POS_Z);
rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y);
out(fir(TOOL_CHANGE, get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool), drill_size));
output_tool_changed();
if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) {
output_tool_zero_begin();
fzr(0.000, FEED_RATE_Z);
// fixme: wondering about the following line
out(fir(TOOL_CHANGE, m_current_tool, drill_size));
output_tool_zero_end();
}
rz(DEFAULT_Z_UP);
out(fr(SPINDLE_ON, SPINDLE_ON_TIME));
output_tool_change_end();
output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH);
last_size = drill_size;
}
// if drill_size != last_size
}
// for
output_file_postamble();
// End of file
// change back to tool 1
out(fi(TOOL_CODE + EOL, 1));
end_gcode();
}
// output
}
// Board
}
// drill
int m_first_spot_drill = YES;
void spot_drill_hole(int x, int y)
{
real drill_x;
real drill_y;
drill_x = scale_x(x);
drill_y = scale_y(y);
save_extents(drill_x, drill_y);
if (m_first_spot_drill) {
output_drill_first_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
m_first_spot_drill = NO;
}
else {
output_drill_hole(drill_x, drill_y, SPOT_DRILL_DEPTH);
}
}
void spot_drill(UL_BOARD B)
{
if (SPOT_DRILL == NO) { return; }
B.holes(H) spot_drill_hole(H.x, H.y);
B.signals(S) S.vias(V) spot_drill_hole(V.x, V.y);
B.elements(E) {
E.package.contacts(C) {
if (C.pad) {
spot_drill_hole(C.pad.x, C.pad.y);
}
}
E.package.holes(H) spot_drill_hole(H.x, H.y);
}
// B.elements
}
string m_lines;
string LINE_SEP = "\n";
string COORD_SEP = ",";
string COORD_FMT = "%8.5f";
string coords(real x1, real y1, real x2, real y2)
{
return frrrr(COORD_FMT + COORD_SEP + COORD_FMT + COORD_SEP +
COORD_FMT + COORD_SEP + COORD_FMT + LINE_SEP, x1, y1, x2, y2);
}
//
// "Draw" on the output device, i.e. the gcode file.
//
// Params:
// x1,y1 Start of the line.
// x2,y2 End of the line.
// state
// z_down
// Returns:
// none
//
real m_arc_begin_x;
real m_arc_begin_y;
int pair_count = 0;
int MAX_COORDS_PER_LINE = 4;
void device_draw(int x1, int y1, int x2, int y2, int state, real z_down)
{
real rx1, ry1, rx2, ry2;
rx1 = scale_x(x1);
ry1 = scale_y(y1);
rx2 = scale_x(x2);
ry2 = scale_y(y2);
save_extents(rx1, ry1);
save_extents(rx2, ry2);
// Output g-code based on the current state.
switch(state) {
// Start of a new line.
case ST_START_LINE:
user_track_begin(rx1, ry1, rx2, ry2);
m_lines += coords(rx1, ry1, rx2, ry2);
rz(DEFAULT_Z_UP);
rxy(rx1, ry1);
fzr(z_down, FEED_RATE_Z);
fxyr(rx2, ry2, FEED_RATE);
pair_count = 0;
break;
// A fill line.
case ST_FILL:
Fatal("Programmer Error", "The Fill functions are no longer supported.");
break;
// Continue a line.
// End a line.
case ST_CONTINUE_LINE:
user_track_continue(rx1, ry1, rx2, ry2);
m_lines += coords(rx1, ry1, rx2, ry2);
if (COMPACT_GCODE == YES) {
if (pair_count == 0) {
fxy(rx2, ry2);
}
else {
xy(rx2, ry2);
}
pair_count++;
}
else {
fxy(rx2, ry2);
}
break;
case ST_END_LINE:
user_track_end(rx1, ry1, rx2, ry2);
m_lines += coords(rx1, ry1, rx2, ry2);
if (COMPACT_GCODE == YES) {
xy(rx2, ry2);
pair_count = 0;
}
else {
fxy(rx2, ry2);
}
break;
// Drill a hole.
// todo is this valid?
case ST_DRILL:
printf("cause an error if used %d");
// printf("drill (%f, %f)\n", rx2, ry2);
break;
// Create an arc.
case ST_ARC_BEGIN:
user_arc_begin(rx1, ry1, rx2, ry2);
m_arc_begin_x = rx1;
m_arc_begin_y = ry1;
break;
// Finish an arc.
case ST_ARC_END:
user_arc_end(rx1, ry1, rx2, ry2);
real cx = rx2;
real cy = ry2;
real end_x = rx1;
real end_y = ry1;
if (1 /* USE_IJ_RELATIVE */) {
cx = rx2 - rx1;
cy = ry2 - ry1;
}
rz(DEFAULT_Z_UP);
rxy(end_x, end_y);
fzr(z_down, FEED_RATE_Z);
if (g_side == TOP || MIRROR_BOTTOM == YES) {
out(frrrr(CIRCLE_TOP, m_arc_begin_x, m_arc_begin_y, cx, cy));
}
else {
out(frrrr(CIRCLE_BOTTOM, m_arc_begin_x, m_arc_begin_y, cx, cy));
}
break;
}
// switch(state)
}
// device_draw
//
// Generate polygons for outline or fill.
// This creates a series of commands for Eagle and puts them
// in g_cmd to be passed when we exit from this phase of pcb-gcode.
//
// Params:
// which_side The side to operate on.
// Return:
// none
//
void generate_outlines(int which_side)
{
string cmd_temp = "";
g_cmd = "";
if (which_side == TOP)
m_layer = TOP_LAYER;
else
m_layer = BOTTOM_LAYER;
board(B) {
real f = BORDER_SIZE;
real x1 = units(B.area.x1) - f;
real y1 = units(B.area.y1) - f;
real x2 = units(B.area.x2) + f;
real y2 = units(B.area.y2) + f;
B.signals(S) {
if (S.name == OUTLINES_SIGNAL_NAME) {
sprintf(cmd_temp, "delete (%f %f) (%f %f);\n",
x1, y1, x2, y2);
g_cmd = g_cmd + cmd_temp;
}
}
sprintf(cmd_temp, "grid %s;\n"
"change isolate %f;\n"
"change rank 6;\n"
"change pour solid;\n"
"change width %f;\n"
"change orphans on;\n"
"layer %d;\n"
"polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n"
"ratsnest;\n"
,
UNIT_OF_MEASURE,
m_isolate,
g_width,
m_layer,
OUTLINES_SIGNAL_NAME, g_width,
x1, y1, x2, y1, x2, y2, x1, y2, x1, y1
);
g_cmd = g_cmd + cmd_temp;
return;
}
// board(B)
}
// generate_outlines
void out_lines(string path, string mode)
{
output(path, mode) {
if (m_pass_num == 0) {
printf("# board=%s\n", elided_path(get_filename(), 30));
printf("# tool size=%f\n", g_width);
}
printf("# pass=%d\n", m_pass_num + 1);
printf(m_lines);
}
}
//
// Write text from the Milling layer to a text engraving file.
//
// Params:
// file_name Output filename.
// Return:
// none
//
void output_text_code(string file_name)
{
int state;
int old_x, old_y;
board(B) {
output(get_filename(), "wt") {
user_file_opened(get_filename(), "wt");
output_file_preamble();
// Initialize the device (i.e. the output file).
begin_gcode();
// Process all the wires.
B.texts(T) T.wires(W) {
if ((T.mirror && g_side == BOTTOM) || (! T.mirror && g_side == TOP)) {
// If this is a text layer, check if we should continue
// a line, or start a new one.
if (W.layer == TEXT_LAYER) {
if (W.x1 == old_x && W.y1 == old_y) {
state = ST_CONTINUE_LINE;
}
else {
state = ST_START_LINE;
}
// if this is an arc, it is treated specially.
if (W.arc) {
device_draw( W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, ST_ARC_BEGIN, TEXT_DEPTH);
device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH);
save_extents(W.x1, W.y1);
save_extents(W.x2, W.y2);
state = ST_START_LINE;
}
else {
// Draw the line (i.e. output the gcode for the line).
device_draw(W.x1, W.y1, W.x2, W.y2, state, TEXT_DEPTH);
old_x = W.x2;
old_y = W.y2;
save_extents(W.x1, W.y1);
save_extents(W.x2, W.y2);
}
// if (W.arc)
}
// if (W.layer == TEXT_LAYER)
}
// if (top and bottom check)
}
// T.wires
output_file_postamble();
end_gcode();
user_file_closing();
}
// output
user_file_closed(get_filename(), "wt");
}
// board
g_width = abs(TEXT_DEPTH);
out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
preview();
m_lines = "";
}
// output_text_code
//
// Write layer data to mill files.
//
// Params:
// file_name Output filename.
// Return:
// none
//
void output_mill_code(string file_name)
{
int state;
int old_x, old_y;
board(B) {
output(get_filename(), "wt") {
user_file_opened(get_filename(), "wt");
output_file_preamble();
// Initialize the device (i.e. the output file).
begin_gcode();
// Process all the wires.
B.wires(W) W.pieces(P) {
// If this is a mill layer, check if we should continue
// a line, or start a new one.
if (P.layer == MILL_LAYER) {
if (P.x1 == old_x && P.y1 == old_y) {
state = ST_CONTINUE_LINE;
}
else {
state = ST_START_LINE;
}
// if this is an arc, it is treated specially.
if (P.arc) {
device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, MILLING_DEPTH);
device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH);
save_extents(P.x1, P.y1);
save_extents(P.x2, P.y2);
state = ST_START_LINE;
}
else {
// Draw the line (i.e. output the gcode for the line).
device_draw(P.x1, P.y1, P.x2, P.y2, state, MILLING_DEPTH);
old_x = P.x2;
old_y = P.y2;
save_extents(P.x1, P.y1);
save_extents(P.x2, P.y2);
}
// if (P.arc)
}
// if (P.layer == MILL_LAYER)
}
// pieces
output_file_postamble();
end_gcode();
user_file_closing();
}
// output
user_file_closed(get_filename(), "wt");
}
// board
g_width = abs(MILLING_DEPTH);
out_lines(g_path + "/viewer/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt");
out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt");
preview();
m_lines = "";
}
// output_mill_code
//
// Write polygon lines to the file.
//
// Params:
// which_side Side of the board to work on.
// suffix Suffix of the file.
// task
// Return:
// none
//
void write_outlines(int which_side, string suffix, int task)
{
string mode;
int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN;
int x0, y0;
int first = 1;
int frame_wire;
int state;
if (m_pass_num == 0) {
mode = "wt";
}
else {
mode = "at";
}
g_side = which_side;
switch (which_side) {
case TOP:
m_layer = TOP_LAYER;
break;
case BOTTOM:
m_layer = BOTTOM_LAYER;
break;
case MILL:
m_layer = MILL_LAYER;
break;
case TEXT:
m_layer = TEXT_LAYER;
break;
default:
sprintf(g_debug, "Illegal which_side %d in write_outlines", which_side);
Fatal("Sorry...", g_debug);
}
if (m_layer == MILL_LAYER || m_layer == TEXT_LAYER) {
if (which_side == MILL) {
g_side = TOP;
output_mill_code(m_file_name + "mt" + DEFAULT_EXTENSION);
g_side = BOTTOM;
output_mill_code(m_file_name + "mb" + DEFAULT_EXTENSION);
return;
}
else {
g_side = TOP;
output_text_code(m_file_name + "tt" + DEFAULT_EXTENSION);
g_side = BOTTOM;
output_text_code(m_file_name + "tb" + DEFAULT_EXTENSION);
return;
}
}
// if m_layer == MILL_LAYER
output(get_filename(), mode) {
board(B) {
user_file_opened(get_filename(), mode);
int rubout_layer = -1;
B.layers(L) {
if (strstr(strlwr(L.name), "rubout") != -1) {
if (strstr(strlwr(L.name), "top") != -1 && which_side == TOP) {
rubout_layer = L.number;
}
else if (strstr(strlwr(L.name), "bot") != -1 && which_side == BOTTOM) {
rubout_layer = L.number;
}
}
}
if (rubout_layer != -1) {
B.wires(W) {
if (W.layer == rubout_layer) {
device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN); // fixme needed?
}
}
}
B.signals(S) {
if (S.name == OUTLINES_SIGNAL_NAME) {
S.polygons(P) {
P.wires(W) {
x1 = min(x1, W.x1);
x2 = max(x2, W.x1);
y1 = min(y1, W.y1);
y2 = max(y2, W.y1);
}
if (m_pass_num == 0) {
output_file_preamble();
begin_gcode();
}
else {
output_between_outline_passes();
}
switch (task) {
case TASK_OUTLINES:
// P.contours jtj
P.contours(W) {
if (first) {
x0 = W.x1;
y0 = W.y1;
frame_wire = (x0 == x1 || x0 == x2) && (y0 == y1 || y0 == y2);
state = ST_START_LINE;
first = 0;
}
else if (W.x2 == x0 && W.y2 == y0) {
state = ST_END_LINE;
first = 1;
}
else {
state = ST_CONTINUE_LINE;
}
if (!frame_wire) {
device_draw(W.x1, W.y1, W.x2, W.y2, state, DEFAULT_Z_DOWN);
}
}
// P.contours(W)
break;
case TASK_FILL:
P.fillings(W) {
device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN);
}
break;
}
// switch(task)
if (m_isolate >= ISO_MAX || SINGLE_PASS || task == TASK_FILL) {
output_file_postamble();
rz(DEFAULT_Z_UP);
spot_drill(B);
end_gcode();
}
sprintf(g_cmd, "delete (%f %f) (%f %f);\n",
units(x1), units(y1), units(x2), units(y2)
);
}
// polygons
}
// if(S.name == OUTLINES_SIGNAL_NAME)
}
// signals
}
// board
user_file_closing();
}
// output
user_file_closed(get_filename(), mode);
out_lines(g_path + "/viewer/data/optimize_me.txt", mode);
out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode);
out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode);
out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode);
out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode);
}
// write_outlines
/* string get_phase_name(int phase)
{
return PHASE_NAME[phase];
}
*/
void gen_progress_menu(int phase)
{
output(path_scr[0] + '/' + "source/pcb-gcode-prg.scr") {
printf("MENU \\\n");
for(int i = 1; i < PH_LAST_PHASE; i++) {
if (i == phase) {
printf("--%s-- \\\n", get_phase_name(i));
// " (for TextMate)
}
else {
printf(" %s \\\n", get_phase_name(i));
}
}
printf(";\n");
}
}
// Make sure a board is available to work on.
// todo move towards bottom
if (!board) {
Fatal("No board!", "Please run this program from the board editor");
}
//
// Process command line arguments.
//
switch (OUTPUT_UNITS) {
case U_MICRONS:
UNIT_OF_MEASURE = "mic";
break;
case U_MILLIMETERS:
UNIT_OF_MEASURE = "mm";
break;
case U_MILS:
UNIT_OF_MEASURE = "mil";
break;
case U_INCHES:
UNIT_OF_MEASURE = "inch";
break;
}
if (argv[FILENAME_ARG] == "--setup") {
exit("run pcb-gcode-setup");
}
if (argv[FILENAME_ARG] == "--attr") {
string attrs;
board(B) {
B.attributes(A) {
attrs = attrs + A.name + "\t" + A.value + "\n";
}
}
dlgMessageBox(attrs);
exit(0);
}
if (argv[FILENAME_ARG] == "--help") {
int choice = dlgMessageBox(usage, "+Return to Eagle", "Run Setup Now");
switch (choice) {
// return to eagle
case 0:
exit(0);
break;
// Run setup now
case 1:
exit("run pcb-gcode-setup");
break;
}
exit(0);
}
// Be sure a filename is specified.
if (argv[FILENAME_ARG]) {
m_file_name = argv[FILENAME_ARG];
if (filedir(m_file_name) == "") {
board(B) m_file_name = filedir(B.name) + m_file_name;
}
}
else {
board(B) m_file_name = filesetext(B.name, "");
}
if (FILENAMES_8_CHARACTERS) {
m_file_name = filedir(m_file_name) + strsub(filename(m_file_name), 0, 5);
}
// Use a default width if one is not given.
if (argv[WIDTH_ARG]) {
g_width = strtod(argv[WIDTH_ARG]);
}
else {
g_width = DEFAULT_WIDTH;
}
// Get the isolate parameter or use the default.
if (argv[ISO_ARG]) {
m_isolate = strtod(argv[ISO_ARG]);
}
else {
m_isolate = ISO_MIN;
}
// Get the pass number, or default to first pass (0).
if (argv[PASS_ARG]) {
m_pass_num = strtol(argv[PASS_ARG]);
}
else {
m_pass_num = 0;
}
// Get the phase we are processing, or default to the first one.
if (argv[PHASE_ARG]) {
g_phase = strtol(argv[PHASE_ARG]);
}
else {
g_phase = PH_TOP_OUT_GEN;
}
get_current_profile();
if (g_phase == PH_TOP_OUT_GEN && m_pass_num == 0 && program_is_setup() == NO)
{
exit("run pcb-gcode-setup");
}
//
// Do what we need to for this phase.
//
switch (g_phase) {
case PH_TOP_OUT_GEN:
if (GENERATE_TOP_OUTLINES == YES)
generate_outlines(TOP);
break;
case PH_TOP_OUT_WRITE:
if (GENERATE_TOP_OUTLINES == YES)
write_outlines(TOP, "top", OUTLINES);
break;
case PH_TOP_FILL_GEN:
if (GENERATE_TOP_FILL == YES)
generate_outlines(TOP);
break;
case PH_TOP_FILL_WRITE:
if (GENERATE_TOP_FILL == YES)
write_outlines(TOP, "tf", FILL);
break;
case PH_BOTTOM_OUT_GEN:
if (GENERATE_BOTTOM_OUTLINES == YES)
generate_outlines(BOTTOM);
break;
case PH_BOTTOM_OUT_WRITE:
if (GENERATE_BOTTOM_OUTLINES == YES)
write_outlines(BOTTOM, "bot", OUTLINES);
break;
case PH_BOTTOM_FILL_GEN:
if (GENERATE_BOTTOM_FILL == YES)
generate_outlines(BOTTOM);
break;
case PH_BOTTOM_FILL_WRITE:
if (GENERATE_BOTTOM_FILL == YES)
write_outlines(BOTTOM, "bf", FILL);
break;
case PH_TOP_DRILL:
if (GENERATE_TOP_DRILL == YES)
drill(TOP, "td");
break;
case PH_BOTTOM_DRILL:
if (GENERATE_BOTTOM_DRILL == YES)
drill(BOTTOM, "bd");
break;
case PH_MILL:
if (GENERATE_MILLING == YES)
write_outlines(MILL, "mil", MILL_BOARD);
break;
case PH_TEXT:
if (GENERATE_TEXT == YES)
write_outlines(TEXT, "txt", MILL_TEXT);
break;
default:
sprintf(g_debug, "Illegal phase %d in main routine", g_phase);
Fatal("Sorry...", g_debug);
}
// Set things up for the next phase.
next_phase();
if (SHOW_PROGRESS == YES) {
gen_progress_menu(g_phase);
}
// If this is not the last phase, exit with a command line for
// Eagle to process. The command includes running this program again.
if (g_phase < PH_LAST_PHASE) {
sprintf(g_cmd,
"%s"
"window fit;\n"
"%s"
"run '%s' '%s' '%f' '%f' '%d' '%d';\n",
g_cmd,
(SHOW_PROGRESS) ? "script pcb-gcode-prg.scr;\n" : "",
argv[PROGRAM_NAME_ARG], m_file_name, g_width, m_isolate,
m_pass_num, g_phase
);
exit(g_cmd);
}
else {
g_cmd = "window fit;\n";
if (SHOW_PROGRESS) {
if (RESTORE_MENU_FILE != "") {
g_cmd = g_cmd + "script " + RESTORE_MENU_FILE + ";\n";
}
else {
g_cmd = g_cmd + "menu;\n";
}
}
exit(g_cmd);
}