2013-04-11 05:32:34 +04:00
//
// gpx.c
//
2013-04-17 16:24:05 +04:00
// Created by WHPThomas <me(at)henri(dot)net> on 1/04/13.
2013-04-11 05:32:34 +04:00
//
2013-04-16 20:01:26 +04:00
// Copyright (c) 2013 WHPThomas, All rights reserved.
2013-04-11 05:32:34 +04:00
//
2013-04-12 17:47:40 +04:00
// gpx references ReplicatorG sources from /src/replicatorg/drivers
2013-04-11 05:32:34 +04:00
// which are part of the ReplicatorG project - http://www.replicat.org
// Copyright (c) 2008 Zach Smith
// and Makerbot4GSailfish.java Copyright (C) 2012 Jetty / Dan Newman
//
// 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 2 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, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# include <assert.h>
# include <ctype.h>
2013-11-24 17:04:49 +04:00
//#include <errno.h>
2013-04-11 05:32:34 +04:00
# include <float.h>
# include <math.h>
# include <stdlib.h>
# include <strings.h>
2013-11-24 17:04:49 +04:00
# include <unistd.h>
2013-04-11 05:32:34 +04:00
# include "gpx.h"
2013-04-20 20:40:13 +04:00
# define A 0
# define B 1
2013-11-24 17:04:49 +04:00
# define SHOW(FN) if(gpx->flag.showErrorMessages) FN
# define CALL(FN) if((rval = FN) != 0) return rval
2013-04-11 05:32:34 +04:00
// Machine definitions
2013-04-18 19:01:37 +04:00
// Axis - max_feedrate, home_feedrate, steps_per_mm, endstop;
// Extruder - max_feedrate, steps_per_mm, motor_steps, has_heated_build_platform;
2013-04-11 05:32:34 +04:00
2013-04-28 19:08:43 +04:00
static Machine cupcake_G3 = {
{ 9600 , 500 , 11.767463 , ENDSTOP_IS_MIN } , // x axis
{ 9600 , 500 , 11.767463 , ENDSTOP_IS_MIN } , // y axis
{ 450 , 450 , 320 , ENDSTOP_IS_MIN } , // z axis
{ 7200 , 50.235478806907409 , 400 , 1 } , // a extruder
{ 7200 , 50.235478806907409 , 400 , 0 } , // b extruder
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-28 19:08:43 +04:00
1 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
1 ,
2013-04-28 19:08:43 +04:00
} ;
static Machine cupcake_G4 = {
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // x axis
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // y axis
{ 450 , 450 , 1280 , ENDSTOP_IS_MIN } , // z axis
{ 7200 , 50.235478806907409 , 400 , 1 } , // a extruder
{ 7200 , 50.235478806907409 , 400 , 0 } , // b extruder
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-28 19:08:43 +04:00
1 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
2 ,
2013-04-28 19:08:43 +04:00
} ;
static Machine cupcake_P4 = {
{ 9600 , 500 , 94.13970462 , ENDSTOP_IS_MIN } , // x axis
{ 9600 , 500 , 94.13970462 , ENDSTOP_IS_MIN } , // y axis
{ 450 , 450 , 2560 , ENDSTOP_IS_MIN } , // z axis
{ 7200 , 50.235478806907409 , 400 , 1 } , // a extruder
{ 7200 , 50.235478806907409 , 400 , 0 } , // b extruder
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-28 19:08:43 +04:00
1 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
3 ,
2013-04-28 19:08:43 +04:00
} ;
static Machine cupcake_PP = {
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // x axis
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // y axis
{ 450 , 450 , 1280 , ENDSTOP_IS_MIN } , // z axis
{ 7200 , 100.470957613814818 , 400 , 1 } , // a extruder
{ 7200 , 100.470957613814818 , 400 , 0 } , // b extruder
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-28 19:08:43 +04:00
1 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
4 ,
2013-04-28 19:08:43 +04:00
} ;
2013-04-29 22:26:36 +04:00
// Axis - max_feedrate, home_feedrate, steps_per_mm, endstop;
// Extruder - max_feedrate, steps_per_mm, motor_steps, has_heated_build_platform;
2013-04-28 19:08:43 +04:00
static Machine thing_o_matic_7 = {
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // x axis
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // y axis
{ 1000 , 500 , 200 , ENDSTOP_IS_MAX } , // z axis
{ 1600 , 50.235478806907409 , 1600 , 1 } , // a extruder
{ 1600 , 50.235478806907409 , 1600 , 0 } , // b extruder
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-28 19:08:43 +04:00
1 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
5 ,
2013-04-28 19:08:43 +04:00
} ;
static Machine thing_o_matic_7D = {
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // x axis
{ 9600 , 500 , 47.069852 , ENDSTOP_IS_MIN } , // y axis
{ 1000 , 500 , 200 , ENDSTOP_IS_MAX } , // z axis
{ 1600 , 50.235478806907409 , 1600 , 0 } , // a extruder
{ 1600 , 50.235478806907409 , 1600 , 1 } , // b extruder
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-28 19:08:43 +04:00
2 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
6 ,
2013-04-28 19:08:43 +04:00
} ;
2013-04-29 22:26:36 +04:00
// Axis - max_feedrate, home_feedrate, steps_per_mm, endstop;
// Extruder - max_feedrate, steps_per_mm, motor_steps, has_heated_build_platform;
2013-04-11 05:32:34 +04:00
static Machine replicator_1 = {
{ 18000 , 2500 , 94.139704 , ENDSTOP_IS_MAX } , // x axis
{ 18000 , 2500 , 94.139704 , ENDSTOP_IS_MAX } , // y axis
{ 1170 , 1100 , 400 , ENDSTOP_IS_MIN } , // z axis
{ 1600 , 96.275201870333662468889989185642 , 3200 , 1 } , // a extruder
{ 1600 , 96.275201870333662468889989185642 , 3200 , 0 } , // b extruder
2013-04-17 15:54:52 +04:00
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-13 03:30:11 +04:00
1 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
7 ,
2013-04-13 03:30:11 +04:00
} ;
static Machine replicator_1D = {
{ 18000 , 2500 , 94.139704 , ENDSTOP_IS_MAX } , // x axis
{ 18000 , 2500 , 94.139704 , ENDSTOP_IS_MAX } , // y axis
{ 1170 , 1100 , 400 , ENDSTOP_IS_MIN } , // z axis
{ 1600 , 96.275201870333662468889989185642 , 3200 , 1 } , // a extruder
{ 1600 , 96.275201870333662468889989185642 , 3200 , 0 } , // b extruder
2013-04-17 15:54:52 +04:00
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-13 03:30:11 +04:00
2 , // extruder count
2013-04-11 05:32:34 +04:00
20 , // timeout
2013-11-15 21:17:33 +04:00
8 ,
2013-04-11 05:32:34 +04:00
} ;
2013-04-29 22:26:36 +04:00
// Axis - max_feedrate, home_feedrate, steps_per_mm, endstop;
// Extruder - max_feedrate, steps_per_mm, motor_steps, has_heated_build_platform;
2013-04-11 05:32:34 +04:00
static Machine replicator_2 = {
{ 18000 , 2500 , 88.573186 , ENDSTOP_IS_MAX } , // x axis
{ 18000 , 2500 , 88.573186 , ENDSTOP_IS_MAX } , // y axis
{ 1170 , 1100 , 400 , ENDSTOP_IS_MIN } , // z axis
{ 1600 , 96.275201870333662468889989185642 , 3200 , 0 } , // a extruder
{ 1600 , 96.275201870333662468889989185642 , 3200 , 0 } , // b extruder
2013-04-17 15:54:52 +04:00
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.97 , // nominal packing density
0.4 , // nozzle diameter
2013-04-13 03:30:11 +04:00
1 , // extruder count
2013-04-11 05:32:34 +04:00
20 , // timeout
2013-11-15 21:17:33 +04:00
9 ,
2013-04-11 05:32:34 +04:00
} ;
2013-08-22 15:48:32 +04:00
static Machine replicator_2H = {
{ 18000 , 2500 , 88.573186 , ENDSTOP_IS_MAX } , // x axis
{ 18000 , 2500 , 88.573186 , ENDSTOP_IS_MAX } , // y axis
{ 1170 , 1100 , 400 , ENDSTOP_IS_MIN } , // z axis
{ 1600 , 96.275201870333662468889989185642 , 3200 , 1 } , // a extruder
{ 1600 , 96.275201870333662468889989185642 , 3200 , 0 } , // b extruder
1.75 , // nominal filament diameter
0.97 , // nominal packing density
0.4 , // nozzle diameter
1 , // extruder count
20 , // timeout
2013-11-15 21:17:33 +04:00
10 ,
2013-08-22 15:48:32 +04:00
} ;
2013-04-11 05:32:34 +04:00
static Machine replicator_2X = {
{ 18000 , 2500 , 88.573186 , ENDSTOP_IS_MAX } , // x axis
{ 18000 , 2500 , 88.573186 , ENDSTOP_IS_MAX } , // y axis
{ 1170 , 1100 , 400 , ENDSTOP_IS_MIN } , // z axis
{ 1600 , 96.275201870333662468889989185642 , 3200 , 1 } , // a extruder
2013-04-28 19:08:43 +04:00
{ 1600 , 96.275201870333662468889989185642 , 3200 , 1 } , // b extruder
2013-04-17 15:54:52 +04:00
1.75 , // nominal filament diameter
2013-06-05 17:35:06 +04:00
0.85 , // nominal packing density
0.4 , // nozzle diameter
2013-04-13 03:30:11 +04:00
2 , // extruder count
2013-04-11 05:32:34 +04:00
20 , // timeout
2013-11-15 21:17:33 +04:00
11 ,
2013-04-11 05:32:34 +04:00
} ;
2013-11-24 17:04:49 +04:00
# define MACHINE_IS(m) strcasecmp(machine, m) == 0
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
int gpx_set_machine ( Gpx * gpx , char * machine )
{
// only load/clobber the on-board machine definition if the one specified is different
if ( MACHINE_IS ( " c3 " ) ) {
if ( gpx - > machine . type ! = 1 ) {
gpx - > machine = cupcake_G3 ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Cupcake Gen3 XYZ, Mk5/6 + Gen4 Extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m c3 " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " c4 " ) ) {
if ( gpx - > machine . type ! = 2 ) {
gpx - > machine = cupcake_G4 ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Cupcake Gen4 XYZ, Mk5/6 + Gen4 Extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m c4 " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " cp4 " ) ) {
if ( gpx - > machine . type ! = 3 ) {
gpx - > machine = cupcake_P4 ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Cupcake Pololu XYZ, Mk5/6 + Gen4 Extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m cp4 " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " cpp " ) ) {
if ( gpx - > machine . type ! = 4 ) {
gpx - > machine = cupcake_PP ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Cupcake Pololu XYZ, Mk5/6 + Pololu Extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m cpp " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " t6 " ) ) {
if ( gpx - > machine . type ! = 5 ) {
gpx - > machine = thing_o_matic_7 ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: TOM Mk6 - single extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m t6 " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " t7 " ) ) {
if ( gpx - > machine . type ! = 5 ) {
gpx - > machine = thing_o_matic_7 ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: TOM Mk7 - single extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m t7 " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " t7d " ) ) {
if ( gpx - > machine . type ! = 6 ) {
gpx - > machine = thing_o_matic_7D ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: TOM Mk7 - dual extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m t7d " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " r1 " ) ) {
if ( gpx - > machine . type ! = 7 ) {
gpx - > machine = replicator_1 ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Replicator 1 - single extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m r1 " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " r1d " ) ) {
if ( gpx - > machine . type ! = 8 ) {
gpx - > machine = replicator_1D ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Replicator 1 - dual extruder " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m r1d " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " r2 " ) ) {
if ( gpx - > machine . type ! = 9 ) {
gpx - > machine = replicator_2 ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Replicator 2 " EOL , stderr ) ;
}
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m r2 " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " r2h " ) ) {
if ( gpx - > machine . type ! = 10 ) {
gpx - > machine = replicator_2H ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Replicator 2 with HBP " EOL , stderr ) ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m r2h " EOL , stderr ) ;
}
else if ( MACHINE_IS ( " r2x " ) ) {
if ( gpx - > machine . type ! = 11 ) {
gpx - > machine = replicator_2X ;
if ( gpx - > flag . verboseMode ) fputs ( " Loading machine definition: Replicator 2X " EOL , stderr ) ;
2013-04-25 15:46:44 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( gpx - > flag . verboseMode ) fputs ( " Ignoring duplicate machine definition: -m r2x " EOL , stderr ) ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
else {
return 1 ;
}
return 0 ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
// PRIVATE FUNCTION PROTOTYPES
static double get_home_feedrate ( Gpx * gpx , int flag ) ;
static int pause_at_zpos ( Gpx * gpx , float z_positon ) ;
2013-04-16 20:01:26 +04:00
// initialization of global variables
2013-11-24 17:04:49 +04:00
void gpx_initialize ( Gpx * gpx , int firstTime )
2013-04-12 17:47:40 +04:00
{
int i ;
2013-11-24 17:04:49 +04:00
gpx - > buffer . ptr = gpx - > buffer . out ;
2013-04-12 17:47:40 +04:00
// we default to using pipes
2013-11-24 17:04:49 +04:00
// initialise machine
if ( firstTime ) gpx - > machine = replicator_2 ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
// initialise command
gpx - > command . x = 0.0 ;
gpx - > command . y = 0.0 ;
gpx - > command . z = 0.0 ;
gpx - > command . a = 0.0 ;
gpx - > command . b = 0.0 ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
gpx - > command . e = 0.0 ;
gpx - > command . f = 0.0 ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
gpx - > command . p = 0.0 ;
gpx - > command . r = 0.0 ;
gpx - > command . s = 0.0 ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
gpx - > command . g = 0.0 ;
gpx - > command . m = 0.0 ;
gpx - > command . t = 0.0 ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
gpx - > command . comment = " " ;
gpx - > command . flag = 0 ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
// initialize target position
gpx - > target . position . x = 0.0 ;
gpx - > target . position . y = 0.0 ;
gpx - > target . position . z = 0.0 ;
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
gpx - > target . position . a = 0.0 ;
gpx - > target . position . b = 0.0 ;
gpx - > target . extruder = 0 ;
// initialize current position
gpx - > current . position . x = 0.0 ;
gpx - > current . position . y = 0.0 ;
gpx - > current . position . z = 0.0 ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
gpx - > current . position . a = 0.0 ;
gpx - > current . position . b = 0.0 ;
gpx - > current . positionKnown = 0 ;
gpx - > current . feedrate = get_home_feedrate ( gpx , XYZ_BIT_MASK ) ;
gpx - > current . extruder = 0 ;
gpx - > current . offset = 0 ;
gpx - > current . percent = 0 ;
// initialize the accumulated rounding error
gpx - > excess . a = 0.0 ;
gpx - > excess . b = 0.0 ;
// initialize the G10 offsets
2013-04-12 17:47:40 +04:00
for ( i = 0 ; i < 7 ; i + + ) {
2013-11-24 17:04:49 +04:00
gpx - > offset [ i ] . x = 0.0 ;
gpx - > offset [ i ] . y = 0.0 ;
gpx - > offset [ i ] . z = 0.0 ;
2013-04-12 17:47:40 +04:00
}
2013-05-08 13:37:30 +04:00
2013-11-24 17:04:49 +04:00
// initialize the command line offset
if ( firstTime ) {
gpx - > userOffset . x = 0.0 ;
gpx - > userOffset . y = 0.0 ;
gpx - > userOffset . z = 0.0 ;
}
2013-04-12 17:47:40 +04:00
2013-04-16 20:01:26 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
2013-11-24 17:04:49 +04:00
gpx - > tool [ i ] . motor_enabled = 0 ;
2013-05-03 17:57:14 +04:00
# if ENABLE_SIMULATED_RPM
2013-11-24 17:04:49 +04:00
gpx - > tool [ i ] . rpm = 0 ;
2013-04-21 21:37:12 +04:00
# endif
2013-11-24 17:04:49 +04:00
gpx - > tool [ i ] . nozzle_temperature = 0 ;
gpx - > tool [ i ] . build_platform_temperature = 0 ;
2013-04-18 19:01:37 +04:00
2013-11-24 17:04:49 +04:00
gpx - > override [ i ] . actual_filament_diameter = 0 ;
gpx - > override [ i ] . filament_scale = 1.0 ;
gpx - > override [ i ] . packing_density = 1.0 ;
gpx - > override [ i ] . standby_temperature = 0 ;
gpx - > override [ i ] . active_temperature = 0 ;
gpx - > override [ i ] . build_platform_temperature = 0 ;
}
if ( firstTime ) {
gpx - > filament [ 0 ] . colour = " _null_ " ;
gpx - > filament [ 0 ] . diameter = 0.0 ;
gpx - > filament [ 0 ] . temperature = 0 ;
gpx - > filament [ 0 ] . LED = 0 ;
gpx - > filamentLength = 1 ;
}
if ( firstTime ) gpx - > commandAtIndex = 0 ;
gpx - > commandAtLength = 0 ;
gpx - > commandAtZ = 0.0 ;
// SETTINGS
if ( firstTime ) {
gpx - > sdCardPath = NULL ;
gpx - > buildName = " GPX " GPX_VERSION ;
2013-04-12 17:47:40 +04:00
}
2013-04-18 19:01:37 +04:00
2013-11-24 17:04:49 +04:00
gpx - > flag . relativeCoordinates = 0 ;
gpx - > flag . extruderIsRelative = 0 ;
2013-04-18 19:01:37 +04:00
2013-11-24 17:04:49 +04:00
if ( firstTime ) {
gpx - > flag . reprapFlavor = 1 ; // default is reprap flavor
gpx - > flag . dittoPrinting = 0 ;
gpx - > flag . buildProgress = 0 ;
gpx - > flag . verboseMode = 0 ;
gpx - > flag . rewrite5D = 0 ;
gpx - > flag . serialIO = 0 ;
}
// STATE
2013-04-17 15:54:52 +04:00
2013-11-24 17:04:49 +04:00
gpx - > flag . programState = 0 ;
gpx - > flag . doPauseAtZPos = 0 ;
gpx - > flag . pausePending = 0 ;
gpx - > flag . macrosEnabled = 0 ;
gpx - > flag . framingEnabled = 0 ;
if ( firstTime ) gpx - > flag . showErrorMessages = 1 ;
2013-04-21 21:37:12 +04:00
2013-11-24 17:04:49 +04:00
gpx - > longestDDA = 0 ;
gpx - > layerHeight = 0.34 ;
gpx - > lineNumber = 1 ;
// STATISTICS
2013-06-05 17:35:06 +04:00
2013-11-24 17:04:49 +04:00
gpx - > accumulated . a = 0.0 ;
gpx - > accumulated . b = 0.0 ;
gpx - > accumulated . time = 0.0 ;
gpx - > accumulated . bytes = 0 ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
if ( firstTime ) {
gpx - > total . length = 0.0 ;
gpx - > total . time = 0.0 ;
gpx - > total . bytes = 0 ;
}
// CALLBACK
gpx - > callbackHandler = NULL ;
gpx - > callbackData = NULL ;
2013-04-12 17:47:40 +04:00
}
// STATE
2013-11-24 17:04:49 +04:00
# define start_program() gpx->flag.programState = RUNNING_STATE
# define end_program() gpx->flag.programState = ENDED_STATE
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
# define program_is_ready() gpx->flag.programState < RUNNING_STATE
# define program_is_running() gpx->flag.programState < ENDED_STATE
2013-04-12 17:47:40 +04:00
2013-04-16 20:01:26 +04:00
// IO FUNCTIONS
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static void write_8 ( Gpx * gpx , unsigned char value )
2013-04-25 15:46:44 +04:00
{
2013-11-24 17:04:49 +04:00
* gpx - > buffer . ptr + + = value ;
2013-04-25 15:46:44 +04:00
}
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static void write_16 ( Gpx * gpx , unsigned short value )
2013-04-12 17:47:40 +04:00
{
union {
unsigned short s ;
unsigned char b [ 2 ] ;
} u ;
u . s = value ;
2013-11-24 17:04:49 +04:00
* gpx - > buffer . ptr + + = u . b [ 0 ] ;
* gpx - > buffer . ptr + + = u . b [ 1 ] ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
static void write_32 ( Gpx * gpx , unsigned int value )
2013-04-11 05:32:34 +04:00
{
2013-04-12 17:47:40 +04:00
union {
unsigned int i ;
unsigned char b [ 4 ] ;
} u ;
u . i = value ;
2013-11-24 17:04:49 +04:00
* gpx - > buffer . ptr + + = u . b [ 0 ] ;
* gpx - > buffer . ptr + + = u . b [ 1 ] ;
* gpx - > buffer . ptr + + = u . b [ 2 ] ;
* gpx - > buffer . ptr + + = u . b [ 3 ] ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
static void write_float ( Gpx * gpx , float value )
2013-04-25 15:46:44 +04:00
{
2013-04-12 17:47:40 +04:00
union {
float f ;
unsigned char b [ 4 ] ;
} u ;
u . f = value ;
2013-11-24 17:04:49 +04:00
* gpx - > buffer . ptr + + = u . b [ 0 ] ;
* gpx - > buffer . ptr + + = u . b [ 1 ] ;
* gpx - > buffer . ptr + + = u . b [ 2 ] ;
* gpx - > buffer . ptr + + = u . b [ 3 ] ;
}
static long write_string ( Gpx * gpx , char * string , long length )
{
long l = length ;
while ( l - - ) {
* gpx - > buffer . ptr + + = * string + + ;
2013-04-25 15:46:44 +04:00
}
2013-11-24 17:04:49 +04:00
* gpx - > buffer . ptr + + = ' \0 ' ;
return length ;
2013-04-25 15:46:44 +04:00
}
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
// FRAMING
static unsigned char calculate_crc ( unsigned char * addr , long len )
2013-04-25 15:46:44 +04:00
{
2013-11-24 17:04:49 +04:00
unsigned char data , crc = 0 ;
while ( len - - ) {
data = * addr + + ;
// 8-bit iButton/Maxim/Dallas CRC loop unrolled
crc = crc ^ data ;
// 1
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
// 2
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
// 3
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
// 4
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
// 5
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
// 6
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
// 7
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
// 8
if ( crc & 0x01 ) crc = ( crc > > 1 ) ^ 0x8C ;
else crc > > = 1 ;
}
return crc ;
}
static void begin_frame ( Gpx * gpx )
{
gpx - > buffer . ptr = gpx - > buffer . out ;
if ( gpx - > flag . framingEnabled ) {
gpx - > buffer . out [ 0 ] = 0xD5 ; // synchronization byte
gpx - > buffer . ptr + = 2 ;
}
}
static int end_frame ( Gpx * gpx )
{
if ( gpx - > flag . framingEnabled ) {
unsigned char * start = ( unsigned char * ) gpx - > buffer . out + 2 ;
unsigned char * end = ( unsigned char * ) gpx - > buffer . ptr ;
long frameLength = end - start ;
gpx - > buffer . out [ 1 ] = ( unsigned char ) frameLength ;
* gpx - > buffer . ptr + + = calculate_crc ( start , frameLength ) ;
2013-04-25 15:46:44 +04:00
}
2013-11-24 17:04:49 +04:00
gpx - > accumulated . bytes + = gpx - > buffer . ptr - gpx - > buffer . out ;
if ( gpx - > callbackHandler ) return gpx - > callbackHandler ( gpx , gpx - > callbackData ) ;
return 0 ;
2013-04-12 17:47:40 +04:00
}
2013-04-17 20:47:52 +04:00
// 5D VECTOR FUNCTIONS
2013-04-18 19:01:37 +04:00
// compute the filament scaling factor
2013-11-24 17:04:49 +04:00
static void set_filament_scale ( Gpx * gpx , unsigned extruder_id , double filament_diameter )
2013-04-29 22:26:36 +04:00
{
2013-04-21 21:37:12 +04:00
double actual_radius = filament_diameter / 2 ;
2013-11-24 17:04:49 +04:00
double nominal_radius = gpx - > machine . nominal_filament_diameter / 2 ;
gpx - > override [ extruder_id ] . filament_scale = ( nominal_radius * nominal_radius ) / ( actual_radius * actual_radius ) ;
2013-04-18 19:01:37 +04:00
}
2013-04-16 20:01:26 +04:00
// return the magnitude (length) of the 5D vector
2013-04-12 17:47:40 +04:00
static double magnitude ( int flag , Ptr5d vector )
2013-04-11 05:32:34 +04:00
{
double acc = 0.0 ;
if ( flag & X_IS_SET ) {
acc = vector - > x * vector - > x ;
}
if ( flag & Y_IS_SET ) {
acc + = vector - > y * vector - > y ;
}
if ( flag & Z_IS_SET ) {
acc + = vector - > z * vector - > z ;
}
if ( flag & A_IS_SET ) {
acc + = vector - > a * vector - > a ;
}
if ( flag & B_IS_SET ) {
acc + = vector - > b * vector - > b ;
}
return sqrt ( acc ) ;
}
2013-04-16 20:01:26 +04:00
// return the largest axis in the vector
static double largest_axis ( int flag , Ptr5d vector )
2013-04-11 05:32:34 +04:00
{
2013-04-16 20:01:26 +04:00
double length , rval = 0.0 ;
if ( flag & X_IS_SET ) {
rval = fabs ( vector - > x ) ;
2013-04-11 05:32:34 +04:00
}
2013-04-16 20:01:26 +04:00
if ( flag & Y_IS_SET ) {
length = fabs ( vector - > y ) ;
if ( rval < length ) rval = length ;
}
if ( flag & Z_IS_SET ) {
length = fabs ( vector - > z ) ;
if ( rval < length ) rval = length ;
}
if ( flag & A_IS_SET ) {
length = fabs ( vector - > a ) ;
if ( rval < length ) rval = length ;
}
if ( flag & B_IS_SET ) {
length = fabs ( vector - > b ) ;
if ( rval < length ) rval = length ;
}
return rval ;
}
// calculate the dda for the longest axis for the current machine definition
2013-11-24 17:04:49 +04:00
static int get_longest_dda ( Gpx * gpx )
2013-04-16 20:01:26 +04:00
{
// calculate once
2013-11-24 17:04:49 +04:00
int longestDDA = gpx - > longestDDA ;
2013-04-16 20:01:26 +04:00
if ( longestDDA = = 0 ) {
2013-11-24 17:04:49 +04:00
longestDDA = ( int ) ( 60 * 1000000.0 / ( gpx - > machine . x . max_feedrate * gpx - > machine . x . steps_per_mm ) ) ;
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
int axisDDA = ( int ) ( 60 * 1000000.0 / ( gpx - > machine . y . max_feedrate * gpx - > machine . y . steps_per_mm ) ) ;
2013-04-16 20:01:26 +04:00
if ( longestDDA < axisDDA ) longestDDA = axisDDA ;
2013-11-24 17:04:49 +04:00
axisDDA = ( int ) ( 60 * 1000000.0 / ( gpx - > machine . z . max_feedrate * gpx - > machine . z . steps_per_mm ) ) ;
2013-04-16 20:01:26 +04:00
if ( longestDDA < axisDDA ) longestDDA = axisDDA ;
2013-11-24 17:04:49 +04:00
gpx - > longestDDA = longestDDA ;
2013-04-16 20:01:26 +04:00
}
return longestDDA ;
}
// return the maximum home feedrate
2013-11-24 17:04:49 +04:00
static double get_home_feedrate ( Gpx * gpx , int flag ) {
2013-04-16 20:01:26 +04:00
double feedrate = 0.0 ;
if ( flag & X_IS_SET ) {
2013-11-24 17:04:49 +04:00
feedrate = gpx - > machine . x . home_feedrate ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( flag & Y_IS_SET & & feedrate < gpx - > machine . y . home_feedrate ) {
feedrate = gpx - > machine . y . home_feedrate ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( flag & Z_IS_SET & & feedrate < gpx - > machine . z . home_feedrate ) {
feedrate = gpx - > machine . z . home_feedrate ;
2013-04-16 20:01:26 +04:00
}
return feedrate ;
}
// return the maximum safe feedrate
2013-11-24 17:04:49 +04:00
static double get_safe_feedrate ( Gpx * gpx , int flag , Ptr5d delta ) {
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
double feedrate = gpx - > current . feedrate ;
2013-04-16 20:01:26 +04:00
if ( feedrate = = 0.0 ) {
2013-11-24 17:04:49 +04:00
feedrate = gpx - > machine . x . max_feedrate ;
if ( feedrate < gpx - > machine . y . max_feedrate ) {
feedrate = gpx - > machine . y . max_feedrate ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
if ( feedrate < gpx - > machine . z . max_feedrate ) {
feedrate = gpx - > machine . z . max_feedrate ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
if ( feedrate < gpx - > machine . a . max_feedrate ) {
feedrate = gpx - > machine . a . max_feedrate ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( feedrate < gpx - > machine . b . max_feedrate ) {
feedrate = gpx - > machine . b . max_feedrate ;
2013-04-11 05:32:34 +04:00
}
}
2013-04-16 20:01:26 +04:00
double distance = magnitude ( flag & XYZ_BIT_MASK , delta ) ;
2013-11-24 17:04:49 +04:00
if ( flag & X_IS_SET & & ( feedrate * delta - > x / distance ) > gpx - > machine . x . max_feedrate ) {
feedrate = gpx - > machine . x . max_feedrate * distance / delta - > x ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
if ( flag & Y_IS_SET & & ( feedrate * delta - > y / distance ) > gpx - > machine . y . max_feedrate ) {
feedrate = gpx - > machine . y . max_feedrate * distance / delta - > y ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( flag & Z_IS_SET & & ( feedrate * delta - > z / distance ) > gpx - > machine . z . max_feedrate ) {
feedrate = gpx - > machine . z . max_feedrate * distance / delta - > z ;
2013-04-16 20:01:26 +04:00
}
if ( distance = = 0 ) {
2013-11-24 17:04:49 +04:00
if ( flag & A_IS_SET & & feedrate > gpx - > machine . a . max_feedrate ) {
feedrate = gpx - > machine . a . max_feedrate ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( flag & B_IS_SET & & feedrate > gpx - > machine . b . max_feedrate ) {
feedrate = gpx - > machine . b . max_feedrate ;
2013-04-11 05:32:34 +04:00
}
2013-04-16 20:01:26 +04:00
}
else {
2013-11-24 17:04:49 +04:00
if ( flag & A_IS_SET & & ( feedrate * delta - > a / distance ) > gpx - > machine . a . max_feedrate ) {
feedrate = gpx - > machine . a . max_feedrate * distance / delta - > a ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
if ( flag & B_IS_SET & & ( feedrate * delta - > b / distance ) > gpx - > machine . b . max_feedrate ) {
feedrate = gpx - > machine . b . max_feedrate * distance / delta - > b ;
2013-04-11 05:32:34 +04:00
}
}
return feedrate ;
}
2013-04-17 15:54:52 +04:00
// convert mm to steps using the current machine definition
2013-04-21 21:37:12 +04:00
// IMPORTANT: this command changes the global excess value which accumulates the rounding remainder
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
static Point5d mm_to_steps ( Gpx * gpx , Ptr5d mm , Ptr2d excess )
2013-04-12 17:47:40 +04:00
{
2013-04-16 20:01:26 +04:00
double value ;
2013-04-12 17:47:40 +04:00
Point5d result ;
2013-11-24 17:04:49 +04:00
result . x = round ( mm - > x * gpx - > machine . x . steps_per_mm ) ;
result . y = round ( mm - > y * gpx - > machine . y . steps_per_mm ) ;
result . z = round ( mm - > z * gpx - > machine . z . steps_per_mm ) ;
2013-04-12 17:47:40 +04:00
if ( excess ) {
2013-04-17 15:54:52 +04:00
// accumulate rounding remainder
2013-11-24 17:04:49 +04:00
value = ( mm - > a * gpx - > machine . a . steps_per_mm ) + excess - > a ;
2013-04-16 20:01:26 +04:00
result . a = round ( value ) ;
2013-04-17 15:54:52 +04:00
// changes to excess
2013-04-16 20:01:26 +04:00
excess - > a = value - result . a ;
2013-11-24 17:04:49 +04:00
value = ( mm - > b * gpx - > machine . b . steps_per_mm ) + excess - > b ;
2013-04-16 20:01:26 +04:00
result . b = round ( value ) ;
2013-04-17 15:54:52 +04:00
// changes to excess
2013-04-16 20:01:26 +04:00
excess - > b = value - result . b ;
2013-04-12 17:47:40 +04:00
}
else {
2013-11-24 17:04:49 +04:00
result . a = round ( mm - > a * gpx - > machine . a . steps_per_mm ) ;
result . b = round ( mm - > b * gpx - > machine . b . steps_per_mm ) ;
2013-04-12 17:47:40 +04:00
}
return result ;
}
2013-11-24 17:04:49 +04:00
static Point5d delta_mm ( Gpx * gpx )
2013-11-15 21:17:33 +04:00
{
Point5d deltaMM ;
// compute the relative distance traveled along each axis and convert to steps
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & X_IS_SET ) deltaMM . x = gpx - > target . position . x - gpx - > current . position . x ; else deltaMM . x = 0 ;
if ( gpx - > command . flag & Y_IS_SET ) deltaMM . y = gpx - > target . position . y - gpx - > current . position . y ; else deltaMM . y = 0 ;
if ( gpx - > command . flag & Z_IS_SET ) deltaMM . z = gpx - > target . position . z - gpx - > current . position . z ; else deltaMM . z = 0 ;
if ( gpx - > command . flag & A_IS_SET ) deltaMM . a = gpx - > target . position . a - gpx - > current . position . a ; else deltaMM . a = 0 ;
if ( gpx - > command . flag & B_IS_SET ) deltaMM . b = gpx - > target . position . b - gpx - > current . position . b ; else deltaMM . b = 0 ;
2013-11-15 21:17:33 +04:00
return deltaMM ;
}
2013-11-24 17:04:49 +04:00
static Point5d delta_steps ( Gpx * gpx , Point5d deltaMM )
2013-11-15 21:17:33 +04:00
{
Point5d deltaSteps ;
// compute the relative distance traveled along each axis and convert to steps
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & X_IS_SET ) deltaSteps . x = round ( fabs ( deltaMM . x ) * gpx - > machine . x . steps_per_mm ) ; else deltaSteps . x = 0 ;
if ( gpx - > command . flag & Y_IS_SET ) deltaSteps . y = round ( fabs ( deltaMM . y ) * gpx - > machine . y . steps_per_mm ) ; else deltaSteps . y = 0 ;
if ( gpx - > command . flag & Z_IS_SET ) deltaSteps . z = round ( fabs ( deltaMM . z ) * gpx - > machine . z . steps_per_mm ) ; else deltaSteps . z = 0 ;
if ( gpx - > command . flag & A_IS_SET ) deltaSteps . a = round ( fabs ( deltaMM . a ) * gpx - > machine . a . steps_per_mm ) ; else deltaSteps . a = 0 ;
if ( gpx - > command . flag & B_IS_SET ) deltaSteps . b = round ( fabs ( deltaMM . b ) * gpx - > machine . b . steps_per_mm ) ; else deltaSteps . b = 0 ;
2013-11-15 21:17:33 +04:00
return deltaSteps ;
}
2013-11-24 17:04:49 +04:00
// X3G QUERIES
// 00 - Get version
// 01 - Initialize firmware to boot state
// 02 - Get available buffer size
// 03 - Clear buffer
// 07 - Abort immediately
// 08 - Pause/Resume
// 10 - Tool query
// 11 - Is finished
// 12 - Read from EEPROM
// 13 - Write to EEPROM
// 14 - Capture to file
// 15 - End capture to file
// 16 - Play back capture
// 17 - Reset
// 18 - Get next filename
// 20 - Get build name
// 21 - Get extended position
// 22 - Extended stop
// 23 - Get motherboard status
// 24 - Get build statistics
// 25 - Get communication statistics
// 27 - Get advanced version number
2013-04-11 05:32:34 +04:00
// X3G COMMANDS
// 131 - Find axes minimums
// 132 - Find axes maximums
2013-11-24 17:04:49 +04:00
static int home_axes ( Gpx * gpx , unsigned direction )
2013-04-11 05:32:34 +04:00
{
2013-04-16 20:01:26 +04:00
Point5d unitVector ;
2013-11-24 17:04:49 +04:00
int xyz_flag = gpx - > command . flag & XYZ_BIT_MASK ;
double feedrate = gpx - > command . flag & F_IS_SET ? gpx - > current . feedrate : get_home_feedrate ( gpx , gpx - > command . flag ) ;
2013-04-16 20:01:26 +04:00
double longestAxis = 0.0 ;
2013-04-12 17:47:40 +04:00
assert ( direction < = 1 ) ;
2013-04-16 20:01:26 +04:00
2013-04-11 05:32:34 +04:00
// compute the slowest feedrate
2013-04-12 17:47:40 +04:00
if ( xyz_flag & X_IS_SET ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > machine . x . home_feedrate < feedrate ) {
feedrate = gpx - > machine . x . home_feedrate ;
2013-04-11 05:32:34 +04:00
}
2013-04-16 20:01:26 +04:00
unitVector . x = 1 ;
2013-11-24 17:04:49 +04:00
longestAxis = gpx - > machine . x . steps_per_mm ;
2013-04-11 05:32:34 +04:00
// confirm machine compatibility
2013-11-24 17:04:49 +04:00
if ( direction ! = gpx - > machine . x . endstop ) {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: X axis homing to %s endstop " EOL , gpx - > lineNumber , direction ? " maximum " : " minimum " ) ) ;
2013-04-11 05:32:34 +04:00
}
}
2013-04-12 17:47:40 +04:00
if ( xyz_flag & Y_IS_SET ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > machine . y . home_feedrate < feedrate ) {
feedrate = gpx - > machine . y . home_feedrate ;
2013-04-11 05:32:34 +04:00
}
2013-04-16 20:01:26 +04:00
unitVector . y = 1 ;
2013-11-24 17:04:49 +04:00
if ( longestAxis < gpx - > machine . y . steps_per_mm ) {
longestAxis = gpx - > machine . y . steps_per_mm ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( direction ! = gpx - > machine . y . endstop ) {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: Y axis homing to %s endstop " EOL , gpx - > lineNumber , direction ? " maximum " : " minimum " ) ) ;
2013-04-11 05:32:34 +04:00
}
}
2013-04-12 17:47:40 +04:00
if ( xyz_flag & Z_IS_SET ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > machine . z . home_feedrate < feedrate ) {
feedrate = gpx - > machine . z . home_feedrate ;
2013-04-11 05:32:34 +04:00
}
2013-04-16 20:01:26 +04:00
unitVector . z = 1 ;
2013-11-24 17:04:49 +04:00
if ( longestAxis < gpx - > machine . z . steps_per_mm ) {
longestAxis = gpx - > machine . z . steps_per_mm ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( direction ! = gpx - > machine . z . endstop ) {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: Z axis homing to %s endstop " EOL , gpx - > lineNumber , direction ? " maximum " : " minimum " ) ) ;
2013-04-11 05:32:34 +04:00
}
}
2013-04-16 20:01:26 +04:00
// unit vector distance in mm
double distance = magnitude ( xyz_flag , & unitVector ) ;
// move duration in microseconds = distance / feedrate * 60,000,000
double microseconds = distance / feedrate * 60000000.0 ;
// time between steps for longest axis = microseconds / longestStep
unsigned step_delay = ( unsigned ) round ( microseconds / longestAxis ) ;
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
gpx - > accumulated . time + = distance / feedrate * 60 ;
begin_frame ( gpx ) ;
write_8 ( gpx , direction = = ENDSTOP_IS_MIN ? 131 : 132 ) ;
2013-04-12 17:47:40 +04:00
2013-04-11 05:32:34 +04:00
// uint8: Axes bitfield. Axes whose bits are set will be moved.
2013-11-24 17:04:49 +04:00
write_8 ( gpx , xyz_flag ) ;
2013-04-12 17:47:40 +04:00
2013-04-11 05:32:34 +04:00
// uint32: Feedrate, in microseconds between steps on the max delta. (DDA)
2013-11-24 17:04:49 +04:00
write_32 ( gpx , step_delay ) ;
2013-04-12 17:47:40 +04:00
2013-04-11 05:32:34 +04:00
// uint16: Timeout, in seconds.
2013-11-24 17:04:49 +04:00
write_16 ( gpx , gpx - > machine . timeout ) ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
return end_frame ( gpx ) ;
2013-04-11 05:32:34 +04:00
}
// 133 - delay
2013-11-24 17:04:49 +04:00
static int delay ( Gpx * gpx , unsigned milliseconds )
2013-04-11 05:32:34 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 133 ) ;
2013-04-12 17:47:40 +04:00
2013-04-11 05:32:34 +04:00
// uint32: delay, in milliseconds
2013-11-24 17:04:49 +04:00
write_32 ( gpx , milliseconds ) ;
return end_frame ( gpx ) ;
2013-04-11 05:32:34 +04:00
}
2013-04-22 18:22:44 +04:00
// 134 - Change extruder offset
// This is important to use on dual-head Replicators, because the machine needs to know
// the current toolhead in order to apply a calibration offset.
2013-11-24 17:04:49 +04:00
static int change_extruder_offset ( Gpx * gpx , unsigned extruder_id )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
assert ( extruder_id < gpx - > machine . extruder_count ) ;
begin_frame ( gpx ) ;
write_8 ( gpx , 134 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: ID of the extruder to switch to
2013-11-24 17:04:49 +04:00
write_8 ( gpx , extruder_id ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-13 03:30:11 +04:00
// 135 - Wait for extruder ready
2013-04-11 05:32:34 +04:00
2013-11-24 17:04:49 +04:00
static int wait_for_extruder ( Gpx * gpx , unsigned extruder_id , unsigned timeout )
2013-04-11 05:32:34 +04:00
{
2013-11-24 17:04:49 +04:00
assert ( extruder_id < gpx - > machine . extruder_count ) ;
begin_frame ( gpx ) ;
write_8 ( gpx , 135 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: ID of the extruder to wait for
2013-11-24 17:04:49 +04:00
write_8 ( gpx , extruder_id ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint16: delay between query packets sent to the extruder, in ms (nominally 100 ms)
2013-11-24 17:04:49 +04:00
write_16 ( gpx , 100 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint16: Timeout before continuing without extruder ready, in seconds (nominally 1 minute)
2013-11-24 17:04:49 +04:00
write_16 ( gpx , timeout ) ;
return end_frame ( gpx ) ;
2013-04-11 05:32:34 +04:00
}
2013-04-13 03:30:11 +04:00
// 136 - extruder action command
2013-04-12 17:47:40 +04:00
2013-04-22 18:22:44 +04:00
// Action 03 - Set extruder target temperature
2013-04-17 15:54:52 +04:00
2013-11-24 17:04:49 +04:00
static int set_nozzle_temperature ( Gpx * gpx , unsigned extruder_id , unsigned temperature )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
assert ( extruder_id < gpx - > machine . extruder_count ) ;
begin_frame ( gpx ) ;
write_8 ( gpx , 136 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: ID of the extruder to query
2013-11-24 17:04:49 +04:00
write_8 ( gpx , extruder_id ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: Action command to send to the extruder
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 3 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: Length of the extruder command payload (N)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 2 ) ;
2013-04-12 17:47:40 +04:00
// int16: Desired target temperature, in Celsius
2013-11-24 17:04:49 +04:00
write_16 ( gpx , temperature ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-17 15:54:52 +04:00
// Action 12 - Enable / Disable fan
2013-11-24 17:04:49 +04:00
static int set_fan ( Gpx * gpx , unsigned extruder_id , unsigned state )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
assert ( extruder_id < gpx - > machine . extruder_count ) ;
begin_frame ( gpx ) ;
write_8 ( gpx , 136 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: ID of the extruder to query
2013-11-24 17:04:49 +04:00
write_8 ( gpx , extruder_id ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: Action command to send to the extruder
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 12 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: Length of the extruder command payload (N)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 1 ) ;
2013-04-12 17:47:40 +04:00
// uint8: 1 to enable, 0 to disable
2013-11-24 17:04:49 +04:00
write_8 ( gpx , state ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-17 15:54:52 +04:00
// Action 13 - Enable / Disable extra output (blower fan)
2013-11-24 17:04:49 +04:00
/*
WARNING : If you are using Gen 4 electronics ( e . g . a Thing - o - Matic or a
heavily modified Cupcake ) , THEN DO NOT USE M126 / M127 . It can trigger
a bug in the Gen 4 Extruder Controller firmware that will cause the
HBP temperature to go wild . Note that the Extruder Controller is a
separate uprocessor on a separate board . It has it ' s own firmware .
It ' s not clear if the bug is firmware - only or if there is a problem
with electronics as well ( e . g . the HBP FET sees some residual current
from the EXTRA FET and its Vgs / Igs threshold is met and it activates ) .
But , there ' s no fix for the bug since no one has invested the time in
diagnosing this Extruder Controller issue .
- dnewman 22 / 11 / 2013
*/
static int set_valve ( Gpx * gpx , unsigned extruder_id , unsigned state )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
assert ( extruder_id < gpx - > machine . extruder_count ) ;
if ( gpx - > machine . type > = MACHINE_TYPE_REPLICATOR_1 ) {
begin_frame ( gpx ) ;
write_8 ( gpx , 136 ) ;
// uint8: ID of the extruder to query
write_8 ( gpx , extruder_id ) ;
// uint8: Action command to send to the extruder
write_8 ( gpx , 13 ) ;
// uint8: Length of the extruder command payload (N)
write_8 ( gpx , 1 ) ;
// uint8: 1 to enable, 0 to disable
write_8 ( gpx , state ) ;
return end_frame ( gpx ) ;
}
else if ( gpx - > flag . verboseMode ) {
fputs ( " Warning: ignoring M126/M127 with Gen 4 extruder electronics " EOL , stderr ) ;
}
return 0 ;
2013-04-12 17:47:40 +04:00
}
2013-04-17 15:54:52 +04:00
// Action 31 - Set build platform target temperature
2013-11-24 17:04:49 +04:00
static int set_build_platform_temperature ( Gpx * gpx , unsigned extruder_id , unsigned temperature )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
assert ( extruder_id < gpx - > machine . extruder_count ) ;
begin_frame ( gpx ) ;
write_8 ( gpx , 136 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: ID of the extruder to query
2013-11-24 17:04:49 +04:00
write_8 ( gpx , extruder_id ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: Action command to send to the extruder
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 31 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: Length of the extruder command payload (N)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 2 ) ;
2013-04-12 17:47:40 +04:00
// int16: Desired target temperature, in Celsius
2013-11-24 17:04:49 +04:00
write_16 ( gpx , temperature ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-17 15:54:52 +04:00
// 137 - Enable / Disable axes steppers
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static int set_steppers ( Gpx * gpx , unsigned axes , unsigned state )
2013-04-12 17:47:40 +04:00
{
unsigned bitfield = axes & AXES_BIT_MASK ;
if ( state ) {
bitfield | = 0x80 ;
}
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 137 ) ;
2013-04-12 17:47:40 +04:00
// uint8: Bitfield codifying the command (see below)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , bitfield ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
2013-04-21 21:37:12 +04:00
// 139 - Queue absolute point
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
static int queue_absolute_point ( Gpx * gpx )
2013-04-16 20:01:26 +04:00
{
2013-11-24 17:04:49 +04:00
long longestDDA = gpx - > longestDDA ? gpx - > longestDDA : get_longest_dda ( gpx ) ;
Point5d steps = mm_to_steps ( gpx , & gpx - > target . position , & gpx - > excess ) ;
begin_frame ( gpx ) ;
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 139 ) ;
2013-04-16 20:01:26 +04:00
// int32: X coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . x ) ;
2013-04-16 20:01:26 +04:00
// int32: Y coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . y ) ;
2013-04-16 20:01:26 +04:00
// int32: Z coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . z ) ;
2013-04-16 20:01:26 +04:00
// int32: A coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , - ( int ) steps . a ) ;
2013-04-16 20:01:26 +04:00
// int32: B coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , - ( int ) steps . b ) ;
2013-04-16 20:01:26 +04:00
// uint32: Feedrate, in microseconds between steps on the max delta. (DDA)
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) longestDDA ) ;
return end_frame ( gpx ) ;
2013-04-16 20:01:26 +04:00
}
2013-04-11 05:32:34 +04:00
// 140 - Set extended position
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static int set_position ( Gpx * gpx )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
Point5d steps = mm_to_steps ( gpx , & gpx - > current . position , NULL ) ;
begin_frame ( gpx ) ;
write_8 ( gpx , 140 ) ;
2013-04-12 17:47:40 +04:00
// int32: X position, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . x ) ;
2013-04-12 17:47:40 +04:00
// int32: Y position, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . y ) ;
2013-04-12 17:47:40 +04:00
// int32: Z position, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . z ) ;
2013-04-12 17:47:40 +04:00
// int32: A position, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . a ) ;
2013-04-12 17:47:40 +04:00
// int32: B position, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . b ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-13 03:30:11 +04:00
// 141 - Wait for build platform ready
2013-04-11 05:32:34 +04:00
2013-11-24 17:04:49 +04:00
static int wait_for_build_platform ( Gpx * gpx , unsigned extruder_id , int timeout )
2013-04-11 05:32:34 +04:00
{
2013-11-24 17:04:49 +04:00
assert ( extruder_id < gpx - > machine . extruder_count ) ;
begin_frame ( gpx ) ;
write_8 ( gpx , 141 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint8: ID of the extruder platform to wait for
2013-11-24 17:04:49 +04:00
write_8 ( gpx , extruder_id ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint16: delay between query packets sent to the extruder, in ms (nominally 100 ms)
2013-11-24 17:04:49 +04:00
write_16 ( gpx , 100 ) ;
2013-04-12 17:47:40 +04:00
2013-04-13 03:30:11 +04:00
// uint16: Timeout before continuing without extruder ready, in seconds (nominally 1 minute)
2013-11-24 17:04:49 +04:00
write_16 ( gpx , timeout ) ;
return end_frame ( gpx ) ;
2013-04-11 05:32:34 +04:00
}
// 142 - Queue extended point, new style
2013-04-20 20:40:13 +04:00
2013-05-03 17:57:14 +04:00
# if ENABLE_SIMULATED_RPM
2013-11-24 17:04:49 +04:00
static int queue_new_point ( Gpx * gpx , unsigned milliseconds )
2013-04-20 20:40:13 +04:00
{
2013-04-21 21:37:12 +04:00
Point5d target ;
// the function is only called by dwell, which is by definition stationary,
// so set zero relitive position change
target . x = 0 ;
target . y = 0 ;
target . z = 0 ;
target . a = 0 ;
target . b = 0 ;
2013-04-20 20:40:13 +04:00
// if we have a G4 dwell and either the a or b motor is on, 'simulate' a 5D extrusion distance
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ A ] . motor_enabled & & gpx - > tool [ A ] . rpm ) {
double maxrpm = gpx - > machine . a . max_feedrate * gpx - > machine . a . steps_per_mm / gpx - > machine . a . motor_steps ;
double rpm = gpx - > tool [ A ] . rpm > maxrpm ? maxrpm : gpx - > tool [ A ] . rpm ;
2013-04-20 20:40:13 +04:00
double minutes = milliseconds / 60000.0 ;
// minute * revolution/minute
2013-11-24 17:04:49 +04:00
double numRevolutions = minutes * ( gpx - > tool [ A ] . motor_enabled > 0 ? rpm : - rpm ) ;
2013-04-20 20:40:13 +04:00
// steps/revolution * mm/steps
2013-11-24 17:04:49 +04:00
double mmPerRevolution = gpx - > machine . a . motor_steps * ( 1 / gpx - > machine . a . steps_per_mm ) ;
2013-04-20 20:40:13 +04:00
target . a = - ( numRevolutions * mmPerRevolution ) ;
2013-11-24 17:04:49 +04:00
gpx - > command . flag | = A_IS_SET ;
gpx - > accumulated . a + = fabs ( target . a ) ;
2013-04-20 20:40:13 +04:00
}
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ B ] . motor_enabled & & gpx - > tool [ B ] . rpm ) {
double maxrpm = gpx - > machine . b . max_feedrate * gpx - > machine . b . steps_per_mm / gpx - > machine . b . motor_steps ;
double rpm = gpx - > tool [ B ] . rpm > maxrpm ? maxrpm : gpx - > tool [ B ] . rpm ;
2013-04-20 20:40:13 +04:00
double minutes = milliseconds / 60000.0 ;
// minute * revolution/minute
2013-11-24 17:04:49 +04:00
double numRevolutions = minutes * ( gpx - > tool [ B ] . motor_enabled > 0 ? rpm : - rpm ) ;
2013-04-20 20:40:13 +04:00
// steps/revolution * mm/steps
2013-11-24 17:04:49 +04:00
double mmPerRevolution = gpx - > machine . b . motor_steps * ( 1 / gpx - > machine . b . steps_per_mm ) ;
2013-04-20 20:40:13 +04:00
target . b = - ( numRevolutions * mmPerRevolution ) ;
2013-11-24 17:04:49 +04:00
gpx - > command . flag | = B_IS_SET ;
gpx - > accumulated . b + = fabs ( target . a ) ;
2013-04-20 20:40:13 +04:00
}
2013-11-24 17:04:49 +04:00
Point5d steps = mm_to_steps ( gpx , & target , & gpx - > excess ) ;
gpx - > accumulated . time + = milliseconds / 1000.0 ;
begin_frame ( gpx ) ;
2013-04-20 20:40:13 +04:00
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 142 ) ;
2013-04-20 20:40:13 +04:00
// int32: X coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . x ) ;
2013-04-20 20:40:13 +04:00
// int32: Y coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . y ) ;
2013-04-20 20:40:13 +04:00
// int32: Z coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . z ) ;
2013-04-20 20:40:13 +04:00
// int32: A coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . a ) ;
2013-04-20 20:40:13 +04:00
// int32: B coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . b ) ;
2013-04-20 20:40:13 +04:00
// uint32: Duration of the movement, in microseconds
2013-11-24 17:04:49 +04:00
write_32 ( gpx , milliseconds * 1000.0 ) ;
2013-04-20 20:40:13 +04:00
// uint8: Axes bitfield to specify which axes are relative. Any axis with a bit set should make a relative movement.
2013-11-24 17:04:49 +04:00
write_8 ( gpx , AXES_BIT_MASK ) ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
return end_frame ( gpx ) ;
2013-04-20 20:40:13 +04:00
}
2013-04-21 21:37:12 +04:00
# endif
2013-04-20 20:40:13 +04:00
2013-04-11 05:32:34 +04:00
// 143 - Store home positions
2013-11-24 17:04:49 +04:00
static int store_home_positions ( Gpx * gpx )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 143 ) ;
2013-04-12 17:47:40 +04:00
// uint8: Axes bitfield to specify which axes' positions to store.
// Any axis with a bit set should have its position stored.
2013-11-24 17:04:49 +04:00
write_8 ( gpx , gpx - > command . flag & AXES_BIT_MASK ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
// 144 - Recall home positions
2013-04-11 05:32:34 +04:00
2013-11-24 17:04:49 +04:00
static int recall_home_positions ( Gpx * gpx )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 144 ) ;
2013-04-12 17:47:40 +04:00
// uint8: Axes bitfield to specify which axes' positions to recall.
// Any axis with a bit set should have its position recalled.
2013-11-24 17:04:49 +04:00
write_8 ( gpx , gpx - > command . flag & AXES_BIT_MASK ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
// 145 - Set digital potentiometer value
2013-11-24 17:04:49 +04:00
static int set_pot_value ( Gpx * gpx , unsigned axis , unsigned value )
2013-04-11 05:32:34 +04:00
{
2013-04-12 17:47:40 +04:00
assert ( axis < = 4 ) ;
assert ( value < = 127 ) ;
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 145 ) ;
2013-04-12 17:47:40 +04:00
2013-04-11 05:32:34 +04:00
// uint8: axis value (valid range 0-4) which axis pot to set
2013-11-24 17:04:49 +04:00
write_8 ( gpx , axis ) ;
2013-04-12 17:47:40 +04:00
2013-04-11 05:32:34 +04:00
// uint8: value (valid range 0-127), values over max will be capped at max
2013-11-24 17:04:49 +04:00
write_8 ( gpx , value ) ;
return end_frame ( gpx ) ;
2013-04-11 05:32:34 +04:00
}
// 146 - Set RGB LED value
2013-04-17 15:54:52 +04:00
2013-11-24 17:04:49 +04:00
static int set_LED ( Gpx * gpx , unsigned red , unsigned green , unsigned blue , unsigned blink )
2013-04-17 15:54:52 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 146 ) ;
2013-04-17 15:54:52 +04:00
// uint8: red value (all pix are 0-255)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , red ) ;
2013-04-17 15:54:52 +04:00
// uint8: green
2013-11-24 17:04:49 +04:00
write_8 ( gpx , green ) ;
2013-04-17 15:54:52 +04:00
// uint8: blue
2013-11-24 17:04:49 +04:00
write_8 ( gpx , blue ) ;
2013-04-17 15:54:52 +04:00
// uint8: blink rate (0-255 valid)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , blink ) ;
2013-04-17 15:54:52 +04:00
// uint8: 0 (reserved for future use)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 0 ) ;
return end_frame ( gpx ) ;
2013-04-17 15:54:52 +04:00
}
2013-04-21 21:37:12 +04:00
2013-11-24 17:04:49 +04:00
static int set_LED_RGB ( Gpx * gpx , unsigned rgb , unsigned blink )
2013-04-21 21:37:12 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 146 ) ;
2013-04-21 21:37:12 +04:00
// uint8: red value (all pix are 0-255)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , ( rgb > > 16 ) & 0xFF ) ;
2013-04-21 21:37:12 +04:00
// uint8: green
2013-11-24 17:04:49 +04:00
write_8 ( gpx , ( rgb > > 8 ) & 0xFF ) ;
2013-04-21 21:37:12 +04:00
// uint8: blue
2013-11-24 17:04:49 +04:00
write_8 ( gpx , rgb & 0xFF ) ;
2013-04-21 21:37:12 +04:00
// uint8: blink rate (0-255 valid)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , blink ) ;
2013-04-21 21:37:12 +04:00
// uint8: 0 (reserved for future use)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 0 ) ;
2013-04-21 21:37:12 +04:00
2013-11-24 17:04:49 +04:00
return end_frame ( gpx ) ;
2013-04-21 21:37:12 +04:00
}
2013-04-11 05:32:34 +04:00
// 147 - Set Beep
2013-04-17 15:54:52 +04:00
2013-11-24 17:04:49 +04:00
static int set_beep ( Gpx * gpx , unsigned frequency , unsigned milliseconds )
2013-04-17 15:54:52 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 147 ) ;
2013-04-17 15:54:52 +04:00
// uint16: frequency
2013-11-24 17:04:49 +04:00
write_16 ( gpx , frequency ) ;
2013-04-17 15:54:52 +04:00
// uint16: buzz length in ms
2013-11-24 17:04:49 +04:00
write_16 ( gpx , milliseconds ) ;
2013-04-17 15:54:52 +04:00
// uint8: 0 (reserved for future use)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 0 ) ;
return end_frame ( gpx ) ;
2013-04-17 15:54:52 +04:00
}
2013-04-12 17:47:40 +04:00
// 148 - Pause for button
2013-11-24 17:04:49 +04:00
# define BUTTON_CENTER 0x01
# define BUTTON_RIGHT 0x02
# define BUTTON_LEFT 0x04
# define BUTTON_DOWN 0x08
# define BUTTON_UP 0x10
# define BUTTON_RESET 0x20
// Button options
# define READY_ON_TIMEOUT 0x01 // change to ready state on timeout
# define RESET_ON_TIMEOUT 0x02 // reset on timeout
# define CLEAR_ON_PRESS 0x04 // clear screen on button press
static int wait_for_button ( Gpx * gpx , int button , unsigned timeout , int button_options )
{
begin_frame ( gpx ) ;
write_8 ( gpx , 148 ) ;
// uint8: Bit field of buttons to wait for
write_8 ( gpx , button ) ;
// uint16: Timeout, in seconds. A value of 0 indicates that the command should not time out.
write_16 ( gpx , timeout ) ;
// uint8: Options bitfield
write_8 ( gpx , button_options ) ;
return end_frame ( gpx ) ;
}
2013-04-11 05:32:34 +04:00
// 149 - Display message to LCD
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static int display_message ( Gpx * gpx , char * message , unsigned vPos , unsigned hPos , unsigned timeout , int wait_for_button )
2013-04-12 17:47:40 +04:00
{
2013-04-21 21:37:12 +04:00
assert ( vPos < 4 ) ;
assert ( hPos < 20 ) ;
2013-11-24 17:04:49 +04:00
int rval = 0 ;
2013-04-12 17:47:40 +04:00
long bytesSent = 0 ;
unsigned bitfield = 0 ;
unsigned seconds = 0 ;
2013-04-13 03:30:11 +04:00
unsigned maxLength = hPos ? 20 - hPos : 20 ;
// clip string so it fits in 4 x 20 lcd display buffer
long length = strlen ( message ) ;
if ( vPos | | hPos ) {
if ( length > maxLength ) length = maxLength ;
2013-11-24 17:04:49 +04:00
bitfield | = 0x01 ; //do not clear flag
2013-04-13 03:30:11 +04:00
}
else {
if ( length > 80 ) length = 80 ;
}
2013-04-12 17:47:40 +04:00
while ( bytesSent < length ) {
2013-04-13 03:30:11 +04:00
if ( bytesSent + maxLength > = length ) {
2013-04-12 17:47:40 +04:00
seconds = timeout ;
bitfield | = 0x02 ; // last message in group
if ( wait_for_button ) {
bitfield | = 0x04 ;
}
}
2013-04-22 18:22:44 +04:00
if ( bytesSent > 0 ) {
2013-04-12 17:47:40 +04:00
bitfield | = 0x01 ; //do not clear flag
}
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 149 ) ;
2013-04-12 17:47:40 +04:00
// uint8: Options bitfield (see below)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , bitfield ) ;
2013-04-12 17:47:40 +04:00
// uint8: Horizontal position to display the message at (commonly 0-19)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , hPos ) ;
2013-04-12 17:47:40 +04:00
// uint8: Vertical position to display the message at (commonly 0-3)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , vPos ) ;
2013-04-12 17:47:40 +04:00
// uint8: Timeout, in seconds. If 0, this message will left on the screen
2013-11-24 17:04:49 +04:00
write_8 ( gpx , seconds ) ;
2013-04-12 17:47:40 +04:00
// 1+N bytes: Message to write to the screen, in ASCII, terminated with a null character.
2013-04-17 20:47:52 +04:00
long rowLength = length - bytesSent ;
2013-11-24 17:04:49 +04:00
bytesSent + = write_string ( gpx , message + bytesSent , rowLength < maxLength ? rowLength : maxLength ) ;
rval = end_frame ( gpx ) ;
if ( rval ) break ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
return rval ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
// 150 - Set Build Percentage
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static int set_build_progress ( Gpx * gpx , unsigned percent )
2013-04-12 17:47:40 +04:00
{
if ( percent > 100 ) percent = 100 ;
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 150 ) ;
2013-04-12 17:47:40 +04:00
// uint8: percent (0-100)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , percent ) ;
2013-04-12 17:47:40 +04:00
// uint8: 0 (reserved for future use) (reserved for future use)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 0 ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
// 151 - Queue Song
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static int queue_song ( Gpx * gpx , unsigned song_id )
2013-04-12 17:47:40 +04:00
{
2013-04-16 20:01:26 +04:00
// song ID 0: error tone with 4 cycles
// song ID 1: done tone
// song ID 2: error tone with 2 cycles
2013-04-12 17:47:40 +04:00
assert ( song_id < = 2 ) ;
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 151 ) ;
2013-04-12 17:47:40 +04:00
// uint8: songID: select from a predefined list of songs
2013-11-24 17:04:49 +04:00
write_8 ( gpx , song_id ) ;
return end_frame ( gpx ) ;
}
// 152 - Reset to factory defaults
static int factory_defaults ( Gpx * gpx )
{
begin_frame ( gpx ) ;
write_8 ( gpx , 152 ) ;
// uint8: 0 (reserved for future use)
write_8 ( gpx , 0 ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
// 153 - Build start notification
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static int start_build ( Gpx * gpx , char * filename )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 153 ) ;
2013-04-12 17:47:40 +04:00
// uint32: 0 (reserved for future use)
2013-11-24 17:04:49 +04:00
write_32 ( gpx , 0 ) ;
2013-04-12 17:47:40 +04:00
// 1+N bytes: Name of the build, in ASCII, null terminated
2013-11-24 17:04:49 +04:00
write_string ( gpx , filename , strlen ( filename ) ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
// 154 - Build end notification
2013-04-12 17:47:40 +04:00
2013-11-24 17:04:49 +04:00
static int end_build ( Gpx * gpx )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 154 ) ;
2013-04-12 17:47:40 +04:00
// uint8: 0 (reserved for future use)
2013-11-24 17:04:49 +04:00
write_8 ( gpx , 0 ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
// 155 - Queue extended point x3g
2013-04-17 15:54:52 +04:00
// IMPORTANT: this command updates the parser state
2013-11-24 17:04:49 +04:00
static int queue_ext_point ( Gpx * gpx , double feedrate )
2013-04-11 05:32:34 +04:00
{
2013-04-16 20:01:26 +04:00
// Because we don't know our previous position, we can't calculate the feedrate or
// distance correctly, so we use an unaccelerated command with a fixed DDA
2013-11-24 17:04:49 +04:00
if ( ! gpx - > current . positionKnown ) {
return queue_absolute_point ( gpx ) ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
Point5d deltaMM = delta_mm ( gpx ) ;
Point5d deltaSteps = delta_steps ( gpx , deltaMM ) ;
2013-04-16 20:01:26 +04:00
2013-04-28 19:08:43 +04:00
// check that we have actually moved on at least one axis when the move is
// rounded down to the nearest step
2013-11-24 17:04:49 +04:00
if ( magnitude ( gpx - > command . flag , & deltaSteps ) > 0 ) {
double distance = magnitude ( gpx - > command . flag & XYZ_BIT_MASK , & deltaMM ) ;
2013-06-05 17:35:06 +04:00
// are we moving and extruding?
2013-11-24 17:04:49 +04:00
if ( gpx - > flag . rewrite5D & & ( gpx - > command . flag & ( A_IS_SET | B_IS_SET ) ) & & distance > 0.0001 ) {
2013-06-05 17:35:06 +04:00
double filament_radius , packing_area , packing_scale ;
if ( A_IS_SET & & deltaMM . a > 0.0001 ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > override [ A ] . actual_filament_diameter > 0.0001 ) {
filament_radius = gpx - > override [ A ] . actual_filament_diameter / 2 ;
packing_area = M_PI * filament_radius * filament_radius * gpx - > override [ A ] . packing_density ;
2013-06-05 17:35:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
filament_radius = gpx - > machine . nominal_filament_diameter / 2 ;
packing_area = M_PI * filament_radius * filament_radius * gpx - > machine . nominal_packing_density ;
2013-06-05 17:35:06 +04:00
}
2013-11-24 17:04:49 +04:00
packing_scale = gpx - > machine . nozzle_diameter * gpx - > layerHeight / packing_area ;
2013-06-05 17:35:06 +04:00
if ( deltaMM . a > 0 ) {
deltaMM . a = distance * packing_scale ;
}
else {
deltaMM . a = - ( distance * packing_scale ) ;
}
2013-11-24 17:04:49 +04:00
gpx - > target . position . a = gpx - > current . position . a + deltaMM . a ;
deltaSteps . a = round ( fabs ( deltaMM . a ) * gpx - > machine . a . steps_per_mm ) ;
2013-06-05 17:35:06 +04:00
}
if ( B_IS_SET & & deltaMM . b > 0.0001 ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > override [ B ] . actual_filament_diameter > 0.0001 ) {
filament_radius = gpx - > override [ B ] . actual_filament_diameter / 2 ;
packing_area = M_PI * filament_radius * filament_radius * gpx - > override [ A ] . packing_density ;
2013-06-05 17:35:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
filament_radius = gpx - > machine . nominal_filament_diameter / 2 ;
packing_area = M_PI * filament_radius * filament_radius * gpx - > machine . nominal_packing_density ;
2013-06-05 17:35:06 +04:00
}
2013-11-24 17:04:49 +04:00
packing_scale = gpx - > machine . nozzle_diameter * gpx - > layerHeight / packing_area ;
2013-06-05 17:35:06 +04:00
if ( deltaMM . b > 0 ) {
deltaMM . b = distance * packing_scale ;
}
else {
deltaMM . b = - ( distance * packing_scale ) ;
}
2013-11-24 17:04:49 +04:00
gpx - > target . position . b = gpx - > current . position . b + deltaMM . b ;
deltaSteps . b = round ( fabs ( deltaMM . b ) * gpx - > machine . b . steps_per_mm ) ;
2013-06-05 17:35:06 +04:00
}
}
2013-11-24 17:04:49 +04:00
Point5d target = gpx - > target . position ;
2013-04-16 20:01:26 +04:00
2013-04-17 15:54:52 +04:00
target . a = - deltaMM . a ;
target . b = - deltaMM . b ;
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
gpx - > accumulated . a + = deltaMM . a ;
gpx - > accumulated . b + = deltaMM . b ;
2013-11-15 21:17:33 +04:00
2013-04-16 20:01:26 +04:00
deltaMM . x = fabs ( deltaMM . x ) ;
deltaMM . y = fabs ( deltaMM . y ) ;
deltaMM . z = fabs ( deltaMM . z ) ;
deltaMM . a = fabs ( deltaMM . a ) ;
deltaMM . b = fabs ( deltaMM . b ) ;
2013-11-24 17:04:49 +04:00
feedrate = get_safe_feedrate ( gpx , gpx - > command . flag , & deltaMM ) ;
2013-04-16 20:01:26 +04:00
double minutes = distance / feedrate ;
if ( minutes = = 0 ) {
distance = 0 ;
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & A_IS_SET ) {
2013-04-16 20:01:26 +04:00
distance = deltaMM . a ;
}
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & B_IS_SET & & distance < deltaMM . b ) {
2013-04-16 20:01:26 +04:00
distance = deltaMM . b ;
}
minutes = distance / feedrate ;
}
//convert feedrate to mm/sec
feedrate / = 60.0 ;
2013-04-21 21:37:12 +04:00
2013-05-03 17:57:14 +04:00
# if ENABLE_SIMULATED_RPM
// if either a or b is 0, but their motor is on and turning, 'simulate' a 5D extrusion distance
2013-11-24 17:04:49 +04:00
if ( deltaMM . a = = 0.0 & & gpx - > tool [ A ] . motor_enabled & & gpx - > tool [ A ] . rpm ) {
double maxrpm = gpx - > machine . a . max_feedrate * gpx - > machine . a . steps_per_mm / gpx - > machine . a . motor_steps ;
double rpm = gpx - > tool [ A ] . rpm > maxrpm ? maxrpm : gpx - > tool [ A ] . rpm ;
2013-04-20 20:40:13 +04:00
// minute * revolution/minute
2013-11-24 17:04:49 +04:00
double numRevolutions = minutes * ( gpx - > tool [ A ] . motor_enabled > 0 ? rpm : - rpm ) ;
2013-04-20 20:40:13 +04:00
// steps/revolution * mm/steps
2013-11-24 17:04:49 +04:00
double mmPerRevolution = gpx - > machine . a . motor_steps * ( 1 / gpx - > machine . a . steps_per_mm ) ;
2013-04-20 20:40:13 +04:00
// set distance
deltaMM . a = numRevolutions * mmPerRevolution ;
2013-11-24 17:04:49 +04:00
deltaSteps . a = round ( fabs ( deltaMM . a ) * gpx - > machine . a . steps_per_mm ) ;
2013-04-20 20:40:13 +04:00
target . a = - deltaMM . a ;
2013-04-16 20:01:26 +04:00
}
2013-04-19 18:57:33 +04:00
else {
// disable RPM as soon as we begin 5D printing
2013-11-24 17:04:49 +04:00
gpx - > tool [ A ] . rpm = 0 ;
2013-04-19 18:57:33 +04:00
}
2013-11-24 17:04:49 +04:00
if ( deltaMM . b = = 0.0 & & gpx - > tool [ B ] . motor_enabled & & gpx - > tool [ B ] . rpm ) {
double maxrpm = gpx - > machine . b . max_feedrate * gpx - > machine . b . steps_per_mm / gpx - > machine . b . motor_steps ;
double rpm = gpx - > tool [ B ] . rpm > maxrpm ? maxrpm : gpx - > tool [ B ] . rpm ;
2013-04-20 20:40:13 +04:00
// minute * revolution/minute
2013-11-24 17:04:49 +04:00
double numRevolutions = minutes * ( gpx - > tool [ B ] . motor_enabled > 0 ? rpm : - rpm ) ;
2013-04-20 20:40:13 +04:00
// steps/revolution * mm/steps
2013-11-24 17:04:49 +04:00
double mmPerRevolution = gpx - > machine . b . motor_steps * ( 1 / gpx - > machine . b . steps_per_mm ) ;
2013-04-20 20:40:13 +04:00
// set distance
deltaMM . b = numRevolutions * mmPerRevolution ;
2013-11-24 17:04:49 +04:00
deltaSteps . b = round ( fabs ( deltaMM . b ) * gpx - > machine . b . steps_per_mm ) ;
2013-04-20 20:40:13 +04:00
target . b = - deltaMM . b ;
2013-04-16 20:01:26 +04:00
}
2013-04-19 18:57:33 +04:00
else {
// disable RPM as soon as we begin 5D printing
2013-11-24 17:04:49 +04:00
gpx - > tool [ B ] . rpm = 0 ;
2013-04-19 18:57:33 +04:00
}
2013-04-21 21:37:12 +04:00
# endif
2013-11-24 17:04:49 +04:00
Point5d steps = mm_to_steps ( gpx , & target , & gpx - > excess ) ;
2013-04-16 20:01:26 +04:00
2013-04-20 20:40:13 +04:00
double usec = ( 60000000.0 * minutes ) ;
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
double dda_interval = usec / largest_axis ( gpx - > command . flag , & deltaSteps ) ;
2013-04-16 20:01:26 +04:00
// Convert dda_interval into dda_rate (dda steps per second on the longest axis)
2013-04-20 20:40:13 +04:00
double dda_rate = 1000000.0 / dda_interval ;
2013-11-24 17:04:49 +04:00
gpx - > accumulated . time + = minutes * 60 ;
2013-04-16 20:01:26 +04:00
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 155 ) ;
2013-04-16 20:01:26 +04:00
// int32: X coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . x ) ;
2013-04-16 20:01:26 +04:00
// int32: Y coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . y ) ;
2013-04-16 20:01:26 +04:00
// int32: Z coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . z ) ;
2013-04-16 20:01:26 +04:00
// int32: A coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . a ) ;
2013-04-16 20:01:26 +04:00
// int32: B coordinate, in steps
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( int ) steps . b ) ;
2013-04-16 20:01:26 +04:00
// uint32: DDA Feedrate, in steps/s
2013-11-24 17:04:49 +04:00
write_32 ( gpx , ( unsigned ) dda_rate ) ;
2013-04-16 20:01:26 +04:00
// uint8: Axes bitfield to specify which axes are relative. Any axis with a bit set should make a relative movement.
2013-11-24 17:04:49 +04:00
write_8 ( gpx , A_IS_SET | B_IS_SET ) ;
2013-04-16 20:01:26 +04:00
// float (single precision, 32 bit): mm distance for this move. normal of XYZ if any of these axes are active, and AB for extruder only moves
2013-11-24 17:04:49 +04:00
write_float ( gpx , ( float ) distance ) ;
2013-04-16 20:01:26 +04:00
// uint16: feedrate in mm/s, multiplied by 64 to assist fixed point calculation on the bot
2013-11-24 17:04:49 +04:00
write_16 ( gpx , ( unsigned ) ( feedrate * 64.0 ) ) ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
return end_frame ( gpx ) ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
return 0 ;
2013-04-11 05:32:34 +04:00
}
2013-04-12 17:47:40 +04:00
// 156 - Set segment acceleration
2013-11-24 17:04:49 +04:00
static int set_acceleration ( Gpx * gpx , int state )
2013-04-12 17:47:40 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 156 ) ;
2013-04-12 17:47:40 +04:00
// uint8: 1 to enable, 0 to disable
2013-11-24 17:04:49 +04:00
write_8 ( gpx , state ) ;
return end_frame ( gpx ) ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
// 157 - Stream Version
2013-11-24 17:04:49 +04:00
static int stream_version ( Gpx * gpx )
{
if ( gpx - > machine . type > = MACHINE_TYPE_REPLICATOR_1 ) {
begin_frame ( gpx ) ;
write_8 ( gpx , 157 ) ;
// uint8: x3g version high byte
write_8 ( gpx , STREAM_VERSION_HIGH ) ;
// uint8: x3g version low byte
write_8 ( gpx , STREAM_VERSION_LOW ) ;
// uint8: not implemented
write_8 ( gpx , 0 ) ;
// uint32: not implemented
write_32 ( gpx , 0 ) ;
// uint16: bot type: PID for the intended bot is sent
// Repliator 2/2X (Might Two)
if ( gpx - > machine . type > = MACHINE_TYPE_REPLICATOR_2 ) {
write_16 ( gpx , 0xB015 ) ;
}
// Replicator (Might One)
else {
write_16 ( gpx , 0xD314 ) ;
}
// uint16: not implemented
write_16 ( gpx , 0 ) ;
// uint32: not implemented
write_32 ( gpx , 0 ) ;
// uint32: not implemented
write_32 ( gpx , 0 ) ;
// uint8: not implemented
write_8 ( gpx , 0 ) ;
return end_frame ( gpx ) ;
}
return 0 ;
}
2013-04-19 08:53:34 +04:00
// 158 - Pause @ zPos
2013-11-24 17:04:49 +04:00
static int pause_at_zpos ( Gpx * gpx , float z_positon )
2013-04-19 08:53:34 +04:00
{
2013-11-24 17:04:49 +04:00
begin_frame ( gpx ) ;
write_8 ( gpx , 158 ) ;
2013-04-19 08:53:34 +04:00
// uint8: pause at Z coordinate or 0.0 to disable
2013-11-24 17:04:49 +04:00
write_float ( gpx , z_positon ) ;
return end_frame ( gpx ) ;
2013-04-19 08:53:34 +04:00
}
2013-11-17 18:37:06 +04:00
// COMMAND @ ZPOS FUNCTIONS
// find an existing filament definition
2013-11-24 17:04:49 +04:00
static int find_filament ( Gpx * gpx , char * filament_id )
2013-11-17 18:37:06 +04:00
{
int i , index = - 1 ;
2013-11-24 17:04:49 +04:00
int l = gpx - > filamentLength ;
2013-11-17 18:37:06 +04:00
// a brute force search is generally fastest for low n
2013-11-24 17:04:49 +04:00
for ( i = 0 ; i < l ; i + + ) {
if ( strcmp ( filament_id , gpx - > filament [ i ] . colour ) = = 0 ) {
2013-11-17 18:37:06 +04:00
index = i ;
break ;
}
}
return index ;
}
// add a new filament definition
2013-11-24 17:04:49 +04:00
static int add_filament ( Gpx * gpx , char * filament_id , double diameter , unsigned temperature , unsigned LED )
2013-11-17 18:37:06 +04:00
{
2013-11-24 17:04:49 +04:00
int index = find_filament ( gpx , filament_id ) ;
2013-11-17 18:37:06 +04:00
if ( index < 0 ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > filamentLength < FILAMENT_MAX ) {
index = gpx - > filamentLength + + ;
gpx - > filament [ index ] . colour = strdup ( filament_id ) ;
gpx - > filament [ index ] . diameter = diameter ;
gpx - > filament [ index ] . temperature = temperature ;
gpx - > filament [ index ] . LED = LED ;
2013-11-17 18:37:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Buffer overflow: too many @filament definitions (maximum = %i) " EOL , gpx - > lineNumber , FILAMENT_MAX - 1 ) ) ;
2013-11-17 18:37:06 +04:00
index = 0 ;
}
}
return index ;
}
// append a new command at z function
2013-11-24 17:04:49 +04:00
static int add_command_at ( Gpx * gpx , double z , char * filament_id , unsigned nozzle_temperature , unsigned build_platform_temperature )
2013-11-17 18:37:06 +04:00
{
2013-11-24 17:04:49 +04:00
int rval ;
int index = filament_id ? find_filament ( gpx , filament_id ) : 0 ;
2013-11-17 18:37:06 +04:00
if ( index < 0 ) {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @pause macro with undefined filament name '%s', use a @filament macro to define it " EOL , gpx - > lineNumber , filament_id ) ) ;
2013-11-17 18:37:06 +04:00
index = 0 ;
}
// insert command
2013-11-24 17:04:49 +04:00
if ( gpx - > commandAtLength < COMMAND_AT_MAX ) {
int i = gpx - > commandAtLength ;
if ( z < = gpx - > commandAtZ ) {
2013-11-17 18:37:06 +04:00
// make a space
2013-11-24 17:04:49 +04:00
while ( i > 0 & & z < = gpx - > commandAt [ i - 1 ] . z ) {
gpx - > commandAt [ i ] = gpx - > commandAt [ i - 1 ] ;
2013-11-17 18:37:06 +04:00
i - - ;
}
2013-11-24 17:04:49 +04:00
gpx - > commandAt [ i ] . z = z ;
gpx - > commandAt [ i ] . filament_index = index ;
gpx - > commandAt [ i ] . nozzle_temperature = nozzle_temperature ;
gpx - > commandAt [ i ] . build_platform_temperature = build_platform_temperature ;
gpx - > commandAtZ = gpx - > commandAt [ gpx - > commandAtLength ] . z ;
2013-11-17 18:37:06 +04:00
}
// append command
else {
2013-11-24 17:04:49 +04:00
gpx - > commandAt [ i ] . z = z ;
gpx - > commandAt [ i ] . filament_index = index ;
gpx - > commandAt [ i ] . nozzle_temperature = nozzle_temperature ;
gpx - > commandAt [ i ] . build_platform_temperature = build_platform_temperature ;
gpx - > commandAtZ = z ;
2013-11-17 18:37:06 +04:00
}
// nonzero temperature signals a temperature change, not a pause @ zPos
// so if its the first pause @ zPos que it up
2013-11-24 17:04:49 +04:00
if ( nozzle_temperature = = 0 & & build_platform_temperature = = 0 & & gpx - > commandAtLength = = 0 ) {
if ( gpx - > flag . macrosEnabled ) {
CALL ( pause_at_zpos ( gpx , z ) ) ;
2013-11-17 18:37:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > flag . pausePending = 1 ;
2013-11-17 18:37:06 +04:00
}
}
2013-11-24 17:04:49 +04:00
gpx - > commandAtLength + + ;
2013-11-17 18:37:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Buffer overflow: too many @pause definitions (maximum = %i) " EOL , gpx - > lineNumber , COMMAND_AT_MAX ) ) ;
2013-11-17 18:37:06 +04:00
}
2013-11-24 17:04:49 +04:00
return 0 ;
2013-11-17 18:37:06 +04:00
}
2013-04-29 22:26:36 +04:00
// TARGET POSITION
// calculate target position
2013-11-24 17:04:49 +04:00
static int calculate_target_position ( Gpx * gpx )
2013-04-29 22:26:36 +04:00
{
2013-11-24 17:04:49 +04:00
int rval = 0 ;
// G10 ofset
Point3d userOffset = gpx - > offset [ gpx - > current . offset ] ;
if ( gpx - > flag . macrosEnabled ) {
// plus command line offset
userOffset . x + = gpx - > userOffset . x ;
userOffset . y + = gpx - > userOffset . y ;
userOffset . z + = gpx - > userOffset . z ;
2013-05-14 06:44:55 +04:00
}
2013-04-29 22:26:36 +04:00
// CALCULATE TARGET POSITION
// x
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & X_IS_SET ) {
gpx - > target . position . x = gpx - > flag . relativeCoordinates ? ( gpx - > current . position . x + gpx - > command . x ) : ( gpx - > command . x + userOffset . x ) ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > target . position . x = gpx - > current . position . x ;
2013-04-29 22:26:36 +04:00
}
// y
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & Y_IS_SET ) {
gpx - > target . position . y = gpx - > flag . relativeCoordinates ? ( gpx - > current . position . y + gpx - > command . y ) : ( gpx - > command . y + userOffset . y ) ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > target . position . y = gpx - > current . position . y ;
2013-04-29 22:26:36 +04:00
}
// z
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & Z_IS_SET ) {
gpx - > target . position . z = gpx - > flag . relativeCoordinates ? ( gpx - > current . position . z + gpx - > command . z ) : ( gpx - > command . z + userOffset . z ) ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > target . position . z = gpx - > current . position . z ;
2013-04-29 22:26:36 +04:00
}
2013-05-17 04:59:01 +04:00
2013-04-29 22:26:36 +04:00
// a
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & A_IS_SET ) {
double a = ( gpx - > override [ A ] . filament_scale = = 1.0 ) ? gpx - > command . a : ( gpx - > command . a * gpx - > override [ A ] . filament_scale ) ;
gpx - > target . position . a = ( gpx - > flag . relativeCoordinates | | gpx - > flag . extruderIsRelative ) ? ( gpx - > current . position . a + a ) : a ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > target . position . a = gpx - > current . position . a ;
2013-04-29 22:26:36 +04:00
}
2013-05-17 04:59:01 +04:00
2013-04-29 22:26:36 +04:00
// b
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & B_IS_SET ) {
double b = ( gpx - > override [ B ] . filament_scale = = 1.0 ) ? gpx - > command . b : ( gpx - > command . b * gpx - > override [ B ] . filament_scale ) ;
gpx - > target . position . b = ( gpx - > flag . relativeCoordinates | | gpx - > flag . extruderIsRelative ) ? ( gpx - > current . position . b + b ) : b ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > target . position . b = gpx - > current . position . b ;
2013-04-29 22:26:36 +04:00
}
// update current feedrate
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & F_IS_SET ) {
gpx - > current . feedrate = gpx - > command . f ;
2013-04-29 22:26:36 +04:00
}
// DITTO PRINTING
2013-11-24 17:04:49 +04:00
if ( gpx - > flag . dittoPrinting ) {
if ( gpx - > command . flag & A_IS_SET ) {
gpx - > target . position . b = gpx - > target . position . a ;
gpx - > command . flag | = B_IS_SET ;
2013-04-29 22:26:36 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( gpx - > command . flag & B_IS_SET ) {
gpx - > target . position . a = gpx - > target . position . b ;
gpx - > command . flag | = A_IS_SET ;
2013-04-29 22:26:36 +04:00
}
}
// CHECK FOR COMMAND @ Z POS
// check if there are more commands on the stack
2013-11-24 17:04:49 +04:00
if ( gpx - > flag . macrosEnabled & & gpx - > commandAtIndex < gpx - > commandAtLength ) {
2013-04-29 22:26:36 +04:00
// check if the next command will cross the z threshold
2013-11-24 17:04:49 +04:00
if ( gpx - > commandAt [ gpx - > commandAtIndex ] . z < = gpx - > target . position . z ) {
2013-04-29 22:26:36 +04:00
// is this a temperature change macro?
2013-11-24 17:04:49 +04:00
if ( gpx - > commandAt [ gpx - > commandAtIndex ] . nozzle_temperature | | gpx - > commandAt [ gpx - > commandAtIndex ] . build_platform_temperature ) {
unsigned nozzle_temperature = gpx - > commandAt [ gpx - > commandAtIndex ] . nozzle_temperature ;
unsigned build_platform_temperature = gpx - > commandAt [ gpx - > commandAtIndex ] . build_platform_temperature ;
2013-04-29 22:26:36 +04:00
// make sure the temperature has changed
2013-11-17 18:37:06 +04:00
if ( nozzle_temperature ) {
2013-11-24 17:04:49 +04:00
if ( ( gpx - > current . extruder = = A | | gpx - > tool [ A ] . nozzle_temperature ) & & gpx - > tool [ A ] . nozzle_temperature ! = nozzle_temperature ) {
CALL ( set_nozzle_temperature ( gpx , A , nozzle_temperature ) ) ;
gpx - > tool [ A ] . nozzle_temperature = gpx - > override [ A ] . active_temperature = nozzle_temperature ;
2013-04-29 22:26:36 +04:00
}
2013-11-24 17:04:49 +04:00
if ( ( gpx - > current . extruder = = B | | gpx - > tool [ B ] . nozzle_temperature ) & & gpx - > tool [ B ] . nozzle_temperature ! = nozzle_temperature ) {
CALL ( set_nozzle_temperature ( gpx , B , nozzle_temperature ) ) ;
gpx - > tool [ B ] . nozzle_temperature = gpx - > override [ B ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
}
if ( build_platform_temperature ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > machine . a . has_heated_build_platform & & gpx - > tool [ A ] . build_platform_temperature & & gpx - > tool [ A ] . build_platform_temperature ! = build_platform_temperature ) {
CALL ( set_build_platform_temperature ( gpx , A , build_platform_temperature ) ) ;
gpx - > tool [ A ] . build_platform_temperature = gpx - > override [ A ] . build_platform_temperature = build_platform_temperature ;
2013-11-17 18:37:06 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( gpx - > machine . b . has_heated_build_platform & & gpx - > tool [ B ] . build_platform_temperature & & gpx - > tool [ B ] . build_platform_temperature ! = build_platform_temperature ) {
CALL ( set_build_platform_temperature ( gpx , B , build_platform_temperature ) ) ;
gpx - > tool [ B ] . build_platform_temperature = gpx - > override [ B ] . build_platform_temperature = build_platform_temperature ;
2013-04-29 22:26:36 +04:00
}
}
2013-11-24 17:04:49 +04:00
gpx - > commandAtIndex + + ;
2013-04-29 22:26:36 +04:00
}
// no its a pause macro
2013-11-24 17:04:49 +04:00
else if ( gpx - > commandAt [ gpx - > commandAtIndex ] . z < = gpx - > target . position . z ) {
int index = gpx - > commandAt [ gpx - > commandAtIndex ] . filament_index ;
2013-04-29 22:26:36 +04:00
// override filament diameter
2013-11-24 17:04:49 +04:00
if ( gpx - > filament [ index ] . diameter > 0.0001 ) {
if ( gpx - > flag . dittoPrinting ) {
set_filament_scale ( gpx , B , gpx - > filament [ index ] . diameter ) ;
set_filament_scale ( gpx , A , gpx - > filament [ index ] . diameter ) ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
set_filament_scale ( gpx , gpx - > current . extruder , gpx - > filament [ index ] . diameter ) ;
2013-04-29 22:26:36 +04:00
}
}
// override nozzle temperature
2013-11-24 17:04:49 +04:00
if ( gpx - > filament [ index ] . temperature ) {
unsigned temperature = gpx - > filament [ index ] . temperature ;
if ( gpx - > tool [ gpx - > current . extruder ] . nozzle_temperature ! = temperature ) {
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_nozzle_temperature ( gpx , B , temperature ) ) ;
CALL ( set_nozzle_temperature ( gpx , A , temperature ) ) ;
gpx - > tool [ A ] . nozzle_temperature = gpx - > tool [ B ] . nozzle_temperature = temperature ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
CALL ( set_nozzle_temperature ( gpx , gpx - > current . extruder , temperature ) ) ;
gpx - > tool [ gpx - > current . extruder ] . nozzle_temperature = temperature ;
2013-04-29 22:26:36 +04:00
}
}
}
// override LED colour
2013-11-24 17:04:49 +04:00
if ( gpx - > filament [ index ] . LED ) {
CALL ( set_LED_RGB ( gpx , gpx - > filament [ index ] . LED , 0 ) ) ;
2013-04-29 22:26:36 +04:00
}
2013-11-24 17:04:49 +04:00
gpx - > commandAtIndex + + ;
if ( gpx - > commandAtIndex < gpx - > commandAtLength ) {
gpx - > flag . doPauseAtZPos = COMMAND_QUE_MAX ;
2013-04-29 22:26:36 +04:00
}
}
}
}
2013-11-24 17:04:49 +04:00
return rval ;
2013-04-29 22:26:36 +04:00
}
2013-11-24 17:04:49 +04:00
static void update_current_position ( Gpx * gpx )
2013-06-05 17:35:06 +04:00
{
2013-11-15 21:17:33 +04:00
// the current position to tracks where the print head currently is
2013-11-24 17:04:49 +04:00
if ( gpx - > target . position . z ! = gpx - > current . position . z ) {
2013-06-05 17:35:06 +04:00
// calculate layer height
2013-11-24 17:04:49 +04:00
gpx - > layerHeight = fabs ( gpx - > target . position . z - gpx - > current . position . z ) ;
2013-06-05 17:35:06 +04:00
// check upper bounds
2013-11-24 17:04:49 +04:00
if ( gpx - > layerHeight > ( gpx - > machine . nozzle_diameter * 0.85 ) ) {
gpx - > layerHeight = gpx - > machine . nozzle_diameter * 0.85 ;
2013-06-05 17:35:06 +04:00
}
}
2013-11-24 17:04:49 +04:00
gpx - > current . position = gpx - > target . position ;
gpx - > current . positionKnown = 1 ;
2013-06-05 17:35:06 +04:00
}
2013-04-29 22:26:36 +04:00
// TOOL CHANGE
2013-11-24 17:04:49 +04:00
static int do_tool_change ( Gpx * gpx , int timeout ) {
int rval ;
2013-04-29 22:26:36 +04:00
// set the temperature of current tool to standby (if standby is different to active)
2013-11-24 17:04:49 +04:00
if ( gpx - > override [ gpx - > current . extruder ] . standby_temperature
& & gpx - > override [ gpx - > current . extruder ] . standby_temperature ! = gpx - > tool [ gpx - > current . extruder ] . nozzle_temperature ) {
unsigned temperature = gpx - > override [ gpx - > current . extruder ] . standby_temperature ;
CALL ( set_nozzle_temperature ( gpx , gpx - > current . extruder , temperature ) ) ;
gpx - > tool [ gpx - > current . extruder ] . nozzle_temperature = temperature ;
2013-04-29 22:26:36 +04:00
}
// set the temperature of selected tool to active (if active is different to standby)
2013-11-24 17:04:49 +04:00
if ( gpx - > override [ gpx - > target . extruder ] . active_temperature
& & gpx - > override [ gpx - > target . extruder ] . active_temperature ! = gpx - > tool [ gpx - > target . extruder ] . nozzle_temperature ) {
unsigned temperature = gpx - > override [ gpx - > target . extruder ] . active_temperature ;
CALL ( set_nozzle_temperature ( gpx , gpx - > target . extruder , temperature ) ) ;
gpx - > tool [ gpx - > target . extruder ] . nozzle_temperature = temperature ;
2013-04-29 22:26:36 +04:00
// wait for nozzle to head up
2013-11-24 17:04:49 +04:00
// CALL( wait_for_extruder(gpx, gpx->target.extruder, timeout) );
2013-04-29 22:26:36 +04:00
}
// switch any active G10 offset (G54 or G55)
2013-11-24 17:04:49 +04:00
if ( gpx - > current . offset = = gpx - > current . extruder + 1 ) {
gpx - > current . offset = gpx - > target . extruder + 1 ;
2013-04-29 22:26:36 +04:00
}
// change current toolhead in order to apply the calibration offset
2013-11-24 17:04:49 +04:00
CALL ( change_extruder_offset ( gpx , gpx - > target . extruder ) ) ;
2013-04-29 22:26:36 +04:00
// set current extruder so changes in E are expressed as changes to A or B
2013-11-24 17:04:49 +04:00
gpx - > current . extruder = gpx - > target . extruder ;
return 0 ;
2013-04-29 22:26:36 +04:00
}
2013-04-21 21:37:12 +04:00
// PARSER PRE-PROCESSOR
2013-04-18 21:36:22 +04:00
2013-04-11 05:32:34 +04:00
// return the length of the given file in bytes
static long get_filesize ( FILE * file )
{
long filesize = - 1 ;
fseek ( file , 0L , SEEK_END ) ;
filesize = ftell ( file ) ;
fseek ( file , 0L , SEEK_SET ) ;
return filesize ;
}
2013-04-18 21:36:22 +04:00
// clean up the gcode command for processing
2013-04-11 05:32:34 +04:00
static char * normalize_word ( char * p )
{
// we expect a letter followed by a digit
// [ a-zA-Z] [ +-]? [ 0-9]+ ('.' [ 0-9]*)?
char * s = p + 1 ;
char * e = p ;
while ( isspace ( * s ) ) s + + ;
if ( * s = = ' + ' | | * s = = ' - ' ) {
* e + + = * s + + ;
}
while ( 1 ) {
// skip spaces
if ( isspace ( * s ) ) {
s + + ;
}
// append digits
else if ( isdigit ( * s ) ) {
* e + + = * s + + ;
}
else {
break ;
}
}
if ( * s = = ' . ' ) {
* e + + = * s + + ;
while ( 1 ) {
// skip spaces
if ( isspace ( * s ) ) {
s + + ;
}
// append digits
else if ( isdigit ( * s ) ) {
* e + + = * s + + ;
}
else {
break ;
}
}
}
* e = 0 ;
return s ;
}
2013-04-18 21:36:22 +04:00
// clean up the gcode comment for processing
2013-04-11 05:32:34 +04:00
static char * normalize_comment ( char * p ) {
// strip white space from the end of comment
char * e = p + strlen ( p ) ;
while ( e > p & & isspace ( ( unsigned char ) ( * - - e ) ) ) * e = ' \0 ' ;
// strip white space from the beginning of comment.
while ( isspace ( * p ) ) p + + ;
return p ;
}
2013-04-21 21:37:12 +04:00
// MACRO PARSER
/* format
2013-04-22 18:22:44 +04:00
; @ < STRING > < STRING > < FLOAT > < FLOAT > mm < INTEGER > c # < HEX > ( < STRING > )
MACRO : = ' ; ' ' @ ' COMMAND COMMENT EOL
COMMAND : = PRINTER | ENABLE | FILAMENT | EXTRUDER | SLICER | START | PAUSE
COMMENT : = S + ' ( ' [ ^ ) ] * ' ) ' S +
2013-06-05 17:35:06 +04:00
PRINTER : = ( ' printer ' | ' machine ' | ' slicer ' ) ( TYPE | PACKING_DENSITY | DIAMETER | TEMP | RGB ) +
2013-08-22 15:48:32 +04:00
TYPE : = S + ( ' c3 ' | ' c4 ' | ' cp4 ' | ' cpp ' | ' t6 ' | ' t7 ' | ' t7d ' | ' r1 ' | ' r1d ' | ' r2 ' | ' r2h ' | ' r2x ' )
2013-06-05 17:35:06 +04:00
PACKING_DENSITY : = S + DIGIT + ( ' . ' DIGIT + ) ?
2013-04-22 18:22:44 +04:00
DIAMETER : = S + DIGIT + ( ' . ' DIGIT + ) ? ' m ' ' m ' ?
TEMP : = S + DIGIT + ' c '
RGB : = S + ' # ' HEX HEX HEX HEX HEX HEX ; LED colour
ENABLE : = ' enable ' ( DITTO | PROGRESS )
DITTO : = S + ' ditto ' ; Simulated ditto printing
PROGRESS : = S + ' progress ' ; Override build progress
FILAMENT : = ' filament ' FILAMENT_ID ( DIAMETER | TEMP | RGB ) +
FILAMENT_ID : = S + ALPHA + ALPHA_NUMERIC *
EXTRUDER : = ( ' right ' | ' left ' ) ( FILAMENT_ID | DIAMETER | TEMP ) +
SLICER : = ' slicer ' DIAMETER ; Nominal filament diameter
2013-04-29 22:26:36 +04:00
START : = ' start ' ( FILAMENT_ID | TEMPERATURE )
PAUSE : = ' pause ' ( ZPOS | FILAMENT_ID | TEMPERATURE ) +
2013-04-22 18:22:44 +04:00
ZPOS : = S + DIGIT + ( ' . ' DIGIT + ) ?
2013-04-21 21:37:12 +04:00
*/
# define MACRO_IS(token) strcmp(token, macro) == 0
2013-04-29 22:26:36 +04:00
# define NAME_IS(n) strcasecmp(name, n) == 0
2013-04-21 21:37:12 +04:00
2013-11-24 17:04:49 +04:00
static int parse_macro ( Gpx * gpx , const char * macro , char * p )
2013-04-21 21:37:12 +04:00
{
2013-11-24 17:04:49 +04:00
int rval = 0 ;
2013-04-21 21:37:12 +04:00
char * name = NULL ;
double z = 0.0 ;
double diameter = 0.0 ;
2013-11-17 18:37:06 +04:00
unsigned nozzle_temperature = 0 ;
unsigned build_platform_temperature = 0 ;
2013-04-21 21:37:12 +04:00
unsigned LED = 0 ;
2013-04-29 22:26:36 +04:00
2013-04-21 21:37:12 +04:00
while ( * p ! = 0 ) {
// trim any leading white space
while ( isspace ( * p ) ) p + + ;
if ( isalpha ( * p ) ) {
name = p ;
2013-11-15 21:17:33 +04:00
while ( * p & & isalnum ( * p ) ) p + + ;
2013-04-21 21:37:12 +04:00
if ( * p ) * p + + = 0 ;
}
else if ( isdigit ( * p ) ) {
char * t = p ;
while ( * p & & ! isspace ( * p ) ) p + + ;
if ( * ( p - 1 ) = = ' m ' ) {
diameter = strtod ( t , NULL ) ;
}
else if ( * ( p - 1 ) = = ' c ' ) {
2013-11-17 18:37:06 +04:00
unsigned temperature = atoi ( t ) ;
if ( temperature > HBP_MAX ) {
nozzle_temperature = temperature ;
}
else {
build_platform_temperature = temperature ;
}
2013-04-21 21:37:12 +04:00
}
else {
z = strtod ( t , NULL ) ;
}
if ( * p ) * p + + = 0 ;
}
else if ( * p = = ' # ' ) {
char * t = + + p ;
while ( * p & & ! isspace ( * p ) ) p + + ;
if ( * p ) * p + + = 0 ;
LED = ( unsigned ) strtol ( t , NULL , 16 ) ;
}
else if ( * p = = ' ( ' ) {
2013-11-15 21:17:33 +04:00
char * t = strchr ( p + 1 , ' ) ' ) ;
2013-04-21 21:37:12 +04:00
if ( t ) {
* t = 0 ;
p = t + 1 ;
}
else {
* p = 0 ;
}
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Syntax error: unrecognised macro parameter " EOL , gpx - > lineNumber ) ) ;
2013-04-21 21:37:12 +04:00
break ;
}
}
2013-06-05 17:35:06 +04:00
// ;@printer <TYPE> <PACKING_DENSITY> <DIAMETER>mm <HBP-TEMP>c #<LED-COLOUR>
2013-04-22 18:22:44 +04:00
if ( MACRO_IS ( " machine " ) | | MACRO_IS ( " printer " ) | | MACRO_IS ( " slicer " ) ) {
2013-04-21 21:37:12 +04:00
if ( name ) {
2013-11-24 17:04:49 +04:00
if ( gpx_set_machine ( gpx , name ) ) {
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @%s macro with unrecognised type '%s' " EOL , gpx - > lineNumber , macro , name ) ) ;
2013-04-21 21:37:12 +04:00
}
2013-11-24 17:04:49 +04:00
gpx - > override [ A ] . packing_density = gpx - > machine . nominal_packing_density ;
gpx - > override [ B ] . packing_density = gpx - > machine . nominal_packing_density ;
2013-06-05 17:35:06 +04:00
}
if ( z > 0.0001 ) {
2013-11-24 17:04:49 +04:00
gpx - > machine . nominal_packing_density = z ;
2013-04-21 21:37:12 +04:00
}
2013-11-24 17:04:49 +04:00
if ( diameter > 0.0001 ) gpx - > machine . nominal_filament_diameter = diameter ;
2013-11-17 18:37:06 +04:00
if ( build_platform_temperature ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > machine . a . has_heated_build_platform ) gpx - > override [ A ] . build_platform_temperature = build_platform_temperature ;
else if ( gpx - > machine . b . has_heated_build_platform ) gpx - > override [ B ] . build_platform_temperature = build_platform_temperature ;
2013-04-21 21:37:12 +04:00
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: @%s macro cannot override non-existant heated build platform " EOL , gpx - > lineNumber , macro ) ) ;
2013-04-21 21:37:12 +04:00
}
}
2013-11-24 17:04:49 +04:00
if ( LED ) {
CALL ( set_LED_RGB ( gpx , LED , 0 ) ) ;
}
2013-04-21 21:37:12 +04:00
}
// ;@enable ditto
// ;@enable progress
else if ( MACRO_IS ( " enable " ) ) {
if ( name ) {
2013-04-22 18:22:44 +04:00
if ( NAME_IS ( " ditto " ) ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > machine . extruder_count = = 1 ) {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: ditto printing cannot access non-existant second extruder " EOL , gpx - > lineNumber ) ) ;
gpx - > flag . dittoPrinting = 0 ;
2013-04-22 18:22:44 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > flag . dittoPrinting = 1 ;
2013-04-22 18:22:44 +04:00
}
}
2013-11-24 17:04:49 +04:00
else if ( NAME_IS ( " progress " ) ) gpx - > flag . buildProgress = 1 ;
2013-04-22 18:22:44 +04:00
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @enable macro with unrecognised parameter '%s' " EOL , gpx - > lineNumber , name ) ) ;
2013-04-22 18:22:44 +04:00
}
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Syntax error: @enable macro with missing parameter " EOL , gpx - > lineNumber ) ) ;
2013-04-21 21:37:12 +04:00
}
}
2013-04-29 22:26:36 +04:00
// ;@filament <NAME> <DIAMETER>mm <TEMP>c #<LED-COLOUR>
2013-04-21 21:37:12 +04:00
else if ( MACRO_IS ( " filament " ) ) {
if ( name ) {
2013-11-24 17:04:49 +04:00
add_filament ( gpx , name , diameter , nozzle_temperature , LED ) ;
2013-04-21 21:37:12 +04:00
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @filament macro with missing name " EOL , gpx - > lineNumber ) ) ;
2013-04-22 18:22:44 +04:00
}
}
2013-06-05 17:35:06 +04:00
// ;@right <NAME> <PACKING_DENSITY> <DIAMETER>mm <TEMP>c
2013-04-22 18:22:44 +04:00
else if ( MACRO_IS ( " right " ) ) {
if ( name ) {
2013-11-24 17:04:49 +04:00
int index = find_filament ( gpx , name ) ;
2013-04-22 18:22:44 +04:00
if ( index > 0 ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > filament [ index ] . diameter > 0.0001 ) set_filament_scale ( gpx , A , gpx - > filament [ index ] . diameter ) ;
if ( gpx - > filament [ index ] . temperature ) gpx - > override [ A ] . active_temperature = gpx - > filament [ index ] . temperature ;
return 0 ;
2013-04-22 18:22:44 +04:00
}
2013-04-21 21:37:12 +04:00
}
2013-11-24 17:04:49 +04:00
if ( z > 0.0001 ) gpx - > override [ A ] . packing_density = z ;
if ( diameter > 0.0001 ) set_filament_scale ( gpx , A , diameter ) ;
if ( nozzle_temperature ) gpx - > override [ A ] . active_temperature = nozzle_temperature ;
2013-04-21 21:37:12 +04:00
}
2013-06-05 17:35:06 +04:00
// ;@left <NAME> <PACKING_DENSITY> <DIAMETER>mm <TEMP>c
2013-04-22 18:22:44 +04:00
else if ( MACRO_IS ( " left " ) ) {
if ( name ) {
2013-11-24 17:04:49 +04:00
int index = find_filament ( gpx , name ) ;
2013-04-22 18:22:44 +04:00
if ( index > 0 ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > filament [ index ] . diameter > 0.0001 ) set_filament_scale ( gpx , B , gpx - > filament [ index ] . diameter ) ;
if ( gpx - > filament [ index ] . temperature ) gpx - > override [ B ] . active_temperature = gpx - > filament [ index ] . temperature ;
return 0 ;
2013-04-22 18:22:44 +04:00
}
}
2013-11-24 17:04:49 +04:00
if ( z > 0.0001 ) gpx - > override [ A ] . packing_density = z ;
if ( diameter > 0.0001 ) set_filament_scale ( gpx , B , diameter ) ;
if ( nozzle_temperature ) gpx - > override [ B ] . active_temperature = nozzle_temperature ;
2013-04-22 18:22:44 +04:00
}
// ;@pause <ZPOS> <NAME>
2013-04-21 21:37:12 +04:00
else if ( MACRO_IS ( " pause " ) ) {
2013-04-29 22:26:36 +04:00
if ( z > 0.0001 ) {
2013-11-24 17:04:49 +04:00
CALL ( add_command_at ( gpx , z , name , 0 , 0 ) ) ;
2013-11-17 18:37:06 +04:00
}
else if ( diameter > 0.0001 ) {
2013-11-24 17:04:49 +04:00
CALL ( add_command_at ( gpx , diameter , name , 0 , 0 ) ) ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @pause macro with missing zPos " EOL , gpx - > lineNumber ) ) ;
2013-04-29 22:26:36 +04:00
}
}
// ;@temp <ZPOS> <TEMP>c
// ;@temperature <ZPOS> <TEMP>c
else if ( MACRO_IS ( " temp " ) | | MACRO_IS ( " temperature " ) ) {
2013-11-17 18:37:06 +04:00
if ( nozzle_temperature | | build_platform_temperature ) {
2013-04-29 22:26:36 +04:00
if ( z > 0.0001 ) {
2013-11-24 17:04:49 +04:00
CALL ( add_command_at ( gpx , z , NULL , nozzle_temperature , build_platform_temperature ) ) ;
2013-11-17 18:37:06 +04:00
}
else if ( diameter > 0.0001 ) {
2013-11-24 17:04:49 +04:00
CALL ( add_command_at ( gpx , diameter , NULL , nozzle_temperature , build_platform_temperature ) ) ;
2013-04-29 22:26:36 +04:00
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @%s macro with missing zPos " EOL , gpx - > lineNumber , macro ) ) ;
2013-04-29 22:26:36 +04:00
}
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @%s macro with missing temperature " EOL , gpx - > lineNumber , macro ) ) ;
2013-04-29 22:26:36 +04:00
}
2013-04-21 21:37:12 +04:00
}
2013-04-29 22:26:36 +04:00
// ;@start <NAME> <TEMP>c
2013-04-21 21:37:12 +04:00
else if ( MACRO_IS ( " start " ) ) {
2013-11-17 18:37:06 +04:00
if ( nozzle_temperature | | build_platform_temperature ) {
if ( nozzle_temperature ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ A ] . nozzle_temperature & & gpx - > tool [ A ] . nozzle_temperature ! = nozzle_temperature ) {
if ( program_is_running ( ) ) {
CALL ( set_nozzle_temperature ( gpx , A , nozzle_temperature ) ) ;
}
gpx - > tool [ A ] . nozzle_temperature = gpx - > override [ A ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > override [ A ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ B ] . nozzle_temperature & & gpx - > tool [ B ] . nozzle_temperature ! = nozzle_temperature ) {
if ( program_is_running ( ) ) {
CALL ( set_nozzle_temperature ( gpx , B , nozzle_temperature ) ) ;
}
gpx - > tool [ B ] . nozzle_temperature = gpx - > override [ B ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > override [ B ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
2013-04-21 21:37:12 +04:00
}
2013-11-17 18:37:06 +04:00
if ( build_platform_temperature ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > machine . a . has_heated_build_platform & & gpx - > tool [ A ] . build_platform_temperature & & gpx - > tool [ A ] . build_platform_temperature ! = build_platform_temperature ) {
if ( program_is_running ( ) ) {
CALL ( set_build_platform_temperature ( gpx , A , build_platform_temperature ) ) ;
}
gpx - > tool [ A ] . build_platform_temperature = gpx - > override [ A ] . build_platform_temperature = build_platform_temperature ;
2013-11-17 18:37:06 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( gpx - > machine . b . has_heated_build_platform & & gpx - > tool [ B ] . build_platform_temperature & & gpx - > tool [ B ] . build_platform_temperature ! = build_platform_temperature ) {
if ( program_is_running ( ) ) {
CALL ( set_build_platform_temperature ( gpx , B , build_platform_temperature ) ) ;
}
gpx - > tool [ B ] . build_platform_temperature = gpx - > override [ B ] . build_platform_temperature = build_platform_temperature ;
2013-11-17 18:37:06 +04:00
}
2013-04-21 21:37:12 +04:00
}
}
2013-11-15 21:17:33 +04:00
else if ( name ) {
2013-11-24 17:04:49 +04:00
int index = find_filament ( gpx , name ) ;
2013-04-29 22:26:36 +04:00
if ( index > 0 ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > filament [ index ] . diameter > 0.0001 ) {
if ( gpx - > flag . dittoPrinting ) {
set_filament_scale ( gpx , B , gpx - > filament [ index ] . diameter ) ;
set_filament_scale ( gpx , A , gpx - > filament [ index ] . diameter ) ;
2013-04-29 22:26:36 +04:00
}
2013-11-17 18:37:06 +04:00
else {
2013-11-24 17:04:49 +04:00
set_filament_scale ( gpx , gpx - > current . extruder , gpx - > filament [ index ] . diameter ) ;
2013-04-29 22:26:36 +04:00
}
}
2013-11-24 17:04:49 +04:00
if ( gpx - > filament [ index ] . LED ) {
CALL ( set_LED_RGB ( gpx , gpx - > filament [ index ] . LED , 0 ) ) ;
}
nozzle_temperature = gpx - > filament [ index ] . temperature ;
2013-11-17 18:37:06 +04:00
if ( nozzle_temperature ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ A ] . nozzle_temperature & & gpx - > tool [ A ] . nozzle_temperature ! = nozzle_temperature ) {
if ( program_is_running ( ) ) {
CALL ( set_nozzle_temperature ( gpx , A , nozzle_temperature ) ) ;
}
gpx - > tool [ A ] . nozzle_temperature = gpx - > override [ A ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > override [ A ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ B ] . nozzle_temperature & & gpx - > tool [ B ] . nozzle_temperature ! = nozzle_temperature ) {
if ( program_is_running ( ) ) {
CALL ( set_nozzle_temperature ( gpx , B , nozzle_temperature ) ) ;
}
gpx - > tool [ B ] . nozzle_temperature = gpx - > override [ B ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
else {
2013-11-24 17:04:49 +04:00
gpx - > override [ B ] . active_temperature = nozzle_temperature ;
2013-11-17 18:37:06 +04:00
}
2013-04-29 22:26:36 +04:00
}
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic error: @start with undefined filament name '%s', use a @filament macro to define it " EOL , gpx - > lineNumber , name ? name : " " ) ) ;
2013-04-29 22:26:36 +04:00
}
2013-04-22 18:22:44 +04:00
}
2013-04-21 21:37:12 +04:00
}
2013-05-03 17:57:14 +04:00
// ;@body
else if ( MACRO_IS ( " body " ) ) {
2013-11-24 17:04:49 +04:00
if ( gpx - > flag . pausePending ) {
CALL ( pause_at_zpos ( gpx , gpx - > commandAt [ 0 ] . z ) ) ;
gpx - > flag . pausePending = 0 ;
2013-05-03 17:57:14 +04:00
}
2013-11-24 17:04:49 +04:00
gpx - > flag . macrosEnabled = 1 ;
2013-05-14 06:44:55 +04:00
}
// ;@header
// ;@footer
else if ( MACRO_IS ( " header " ) & & MACRO_IS ( " footer " ) ) {
2013-11-24 17:04:49 +04:00
gpx - > flag . macrosEnabled = 0 ;
2013-05-03 17:57:14 +04:00
}
2013-11-24 17:04:49 +04:00
return 0 ;
2013-04-21 21:37:12 +04:00
}
2013-11-24 17:04:49 +04:00
/*
SIMPLE . INI FILE PARSER
ini . c is released under the New BSD license ( see LICENSE . txt ) . Go to the project
home page for more info : http : //code.google.com/p/inih/
Parse given INI - style file . May have [ section ] s , name = value pairs
( whitespace stripped ) , and comments starting with ' ; ' ( semicolon ) . Section
is " " if name = value pair parsed before any section heading . name : value
pairs are also supported as a concession to Python ' s ConfigParser .
For each name = value pair parsed , call handler function with given user
pointer as well as section , name , and value ( data only valid for duration
of handler call ) . Handler should return 0 on success , nonzero on error .
Returns 0 on success , line number of first error on parse error ( doesn ' t
stop on first error ) , - 1 on file open error .
*/
# define INI_SECTION_MAX 64
# define INI_NAME_MAX 64
/* Nonzero to allow multi-line value parsing, in the style of Python's
ConfigParser . If allowed , ini_parse ( ) will call the handler with the same
name for each subsequent line parsed . */
# ifndef INI_ALLOW_MULTILINE
# define INI_ALLOW_MULTILINE 1
# endif
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
the file . See http : //code.google.com/p/inih/issues/detail?id=21 */
# ifndef INI_ALLOW_BOM
# define INI_ALLOW_BOM 1
# endif
/* Strip whitespace chars off end of given string, in place. Return s. */
static char * rstrip ( char * s )
2013-04-29 22:26:36 +04:00
{
2013-11-24 17:04:49 +04:00
char * p = s + strlen ( s ) ;
while ( p > s & & isspace ( ( unsigned char ) ( * - - p ) ) ) * p = ' \0 ' ;
return s ;
}
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
/* Return pointer to first non-whitespace char in given string. */
static char * lskip ( const char * s )
{
while ( * s & & isspace ( ( unsigned char ) ( * s ) ) ) s + + ;
return ( char * ) s ;
}
/* Return pointer to first char c or ';' comment in given string, or pointer to
null at end of string if neither found . ' ; ' must be prefixed by a whitespace
character to register as a comment . */
static char * find_char_or_comment ( const char * s , char c )
{
int was_whitespace = 0 ;
while ( * s & & * s ! = c & & ! ( was_whitespace & & * s = = ' ; ' ) ) {
was_whitespace = isspace ( ( unsigned char ) ( * s ) ) ;
s + + ;
}
return ( char * ) s ;
}
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char * strncpy0 ( char * dest , const char * src , size_t size )
{
strncpy ( dest , src , size ) ;
dest [ size - 1 ] = ' \0 ' ;
return dest ;
}
/* See documentation in header file. */
static int ini_parse_file ( Gpx * gpx , FILE * file , int ( * handler ) ( Gpx * , const char * , const char * , char * ) )
{
/* Uses a fair bit of stack (use heap instead if you need to) */
char section [ INI_SECTION_MAX ] = " " ;
char prev_name [ INI_NAME_MAX ] = " " ;
char * start ;
char * end ;
char * name ;
char * value ;
int error = 0 ;
gpx - > lineNumber = 0 ;
/* Scan through file line by line */
while ( fgets ( gpx - > buffer . in , BUFFER_MAX , file ) ! = NULL ) {
gpx - > lineNumber + + ;
start = gpx - > buffer . in ;
# if INI_ALLOW_BOM
if ( gpx - > lineNumber = = 1 & & ( unsigned char ) start [ 0 ] = = 0xEF & &
( unsigned char ) start [ 1 ] = = 0xBB & &
( unsigned char ) start [ 2 ] = = 0xBF ) {
start + = 3 ;
2013-05-03 17:57:14 +04:00
}
2013-11-24 17:04:49 +04:00
# endif
start = lskip ( rstrip ( start ) ) ;
if ( * start = = ' ; ' | | * start = = ' # ' ) {
/* Per Python ConfigParser, allow '#' comments at start of line */
2013-06-05 17:35:06 +04:00
}
2013-11-24 17:04:49 +04:00
# if INI_ALLOW_MULTILINE
else if ( * prev_name & & * start & & start > gpx - > buffer . in ) {
/* Non-black line with leading whitespace, treat as continuation
of previous name ' s value ( as per Python ConfigParser ) . */
if ( handler ( gpx , section , prev_name , start ) & & ! error )
error = gpx - > lineNumber ;
2013-08-22 15:48:32 +04:00
}
2013-11-24 17:04:49 +04:00
# endif
else if ( * start = = ' [ ' ) {
/* A "[section]" line */
end = find_char_or_comment ( start + 1 , ' ] ' ) ;
if ( * end = = ' ] ' ) {
* end = ' \0 ' ;
strncpy0 ( section , start + 1 , sizeof ( section ) ) ;
* prev_name = ' \0 ' ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( ! error ) {
/* No ']' found on section line */
error = gpx - > lineNumber ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
}
else if ( * start & & * start ! = ' ; ' ) {
/* Not a comment, must be a name[=:]value pair */
end = find_char_or_comment ( start , ' = ' ) ;
if ( * end ! = ' = ' ) {
end = find_char_or_comment ( start , ' : ' ) ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
if ( * end = = ' = ' | | * end = = ' : ' ) {
* end = ' \0 ' ;
name = rstrip ( start ) ;
value = lskip ( end + 1 ) ;
end = find_char_or_comment ( value , ' \0 ' ) ;
if ( * end = = ' ; ' )
* end = ' \0 ' ;
rstrip ( value ) ;
/* Valid name[=:]value pair found, call handler */
strncpy0 ( prev_name , name , sizeof ( prev_name ) ) ;
if ( handler ( gpx , section , name , value ) & & ! error )
error = gpx - > lineNumber ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( ! error ) {
/* No '=' or ':' found on name[=:]value line */
error = gpx - > lineNumber ;
2013-04-16 20:01:26 +04:00
}
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
}
return error ;
}
/* See documentation in header file. */
static int ini_parse ( Gpx * gpx , const char * filename ,
int ( * handler ) ( Gpx * , const char * , const char * , char * ) )
{
FILE * file ;
int error ;
file = fopen ( filename , " r " ) ;
if ( ! file ) return - 1 ;
error = ini_parse_file ( gpx , file , handler ) ;
fclose ( file ) ;
return error ;
}
// Custom machine definition ini handler
# define SECTION_IS(s) strcasecmp(section, s) == 0
# define PROPERTY_IS(n) strcasecmp(property, n) == 0
# define VALUE_IS(v) strcasecmp(value, v) == 0
int gpx_set_property ( Gpx * gpx , const char * section , const char * property , char * value )
{
int rval ;
if ( SECTION_IS ( " " ) | | SECTION_IS ( " macro " ) ) {
if ( PROPERTY_IS ( " slicer " )
| | PROPERTY_IS ( " filament " )
| | PROPERTY_IS ( " pause " )
| | PROPERTY_IS ( " start " )
| | PROPERTY_IS ( " temp " )
| | PROPERTY_IS ( " temperature " ) ) {
CALL ( parse_macro ( gpx , property , value ) ) ;
2013-04-26 06:53:47 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( PROPERTY_IS ( " verbose " ) ) {
gpx - > flag . verboseMode = atoi ( value ) ;
}
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " printer " ) | | SECTION_IS ( " slicer " ) ) {
if ( PROPERTY_IS ( " ditto_printing " ) ) gpx - > flag . dittoPrinting = atoi ( value ) ;
else if ( PROPERTY_IS ( " build_progress " ) ) gpx - > flag . buildProgress = atoi ( value ) ;
else if ( PROPERTY_IS ( " packing_density " ) ) gpx - > machine . nominal_packing_density = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " recalculate_5d " ) ) gpx - > flag . rewrite5D = atoi ( value ) ;
else if ( PROPERTY_IS ( " nominal_filament_diameter " )
| | PROPERTY_IS ( " slicer_filament_diameter " )
| | PROPERTY_IS ( " filament_diameter " ) ) {
gpx - > machine . nominal_filament_diameter = strtod ( value , NULL ) ;
}
else if ( PROPERTY_IS ( " machine_type " ) ) {
// only load/clobber the on-board machine definition if the one specified is different
if ( gpx_set_machine ( gpx , value ) ) {
SHOW ( fprintf ( stderr , " (line %u) Configuration error: unrecognised machine type '%s' " EOL , gpx - > lineNumber , value ) ) ;
return gpx - > lineNumber ;
2013-04-22 19:16:40 +04:00
}
2013-11-24 17:04:49 +04:00
gpx - > override [ A ] . packing_density = gpx - > machine . nominal_packing_density ;
gpx - > override [ B ] . packing_density = gpx - > machine . nominal_packing_density ;
}
else if ( PROPERTY_IS ( " gcode_flavor " ) ) {
// use on-board machine definition
if ( VALUE_IS ( " reprap " ) ) gpx - > flag . reprapFlavor = 1 ;
else if ( VALUE_IS ( " makerbot " ) ) gpx - > flag . reprapFlavor = 0 ;
2013-04-22 19:16:40 +04:00
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Configuration error: unrecognised GCODE flavor '%s' " EOL , gpx - > lineNumber , value ) ) ;
return gpx - > lineNumber ;
2013-04-22 19:16:40 +04:00
}
}
2013-11-24 17:04:49 +04:00
else if ( PROPERTY_IS ( " build_platform_temperature " ) ) {
if ( gpx - > machine . a . has_heated_build_platform ) gpx - > override [ A ] . build_platform_temperature = atoi ( value ) ;
else if ( gpx - > machine . b . has_heated_build_platform ) gpx - > override [ B ] . build_platform_temperature = atoi ( value ) ;
}
else if ( PROPERTY_IS ( " sd_card_path " ) ) {
gpx - > sdCardPath = strdup ( value ) ;
}
else if ( PROPERTY_IS ( " verbose " ) ) {
gpx - > flag . verboseMode = atoi ( value ) ;
}
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " x " ) ) {
if ( PROPERTY_IS ( " max_feedrate " ) ) gpx - > machine . x . max_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " home_feedrate " ) ) gpx - > machine . x . home_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " steps_per_mm " ) ) gpx - > machine . x . steps_per_mm = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " endstop " ) ) gpx - > machine . x . endstop = atoi ( value ) ;
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " y " ) ) {
if ( PROPERTY_IS ( " max_feedrate " ) ) gpx - > machine . y . max_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " home_feedrate " ) ) gpx - > machine . y . home_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " steps_per_mm " ) ) gpx - > machine . y . steps_per_mm = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " endstop " ) ) gpx - > machine . y . endstop = atoi ( value ) ;
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " z " ) ) {
if ( PROPERTY_IS ( " max_feedrate " ) ) gpx - > machine . z . max_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " home_feedrate " ) ) gpx - > machine . z . home_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " steps_per_mm " ) ) gpx - > machine . z . steps_per_mm = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " endstop " ) ) gpx - > machine . z . endstop = atoi ( value ) ;
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " a " ) ) {
if ( PROPERTY_IS ( " max_feedrate " ) ) gpx - > machine . a . max_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " steps_per_mm " ) ) gpx - > machine . a . steps_per_mm = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " motor_steps " ) ) gpx - > machine . a . motor_steps = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " has_heated_build_platform " ) ) gpx - > machine . a . has_heated_build_platform = atoi ( value ) ;
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " right " ) ) {
if ( PROPERTY_IS ( " active_temperature " )
| | PROPERTY_IS ( " nozzle_temperature " ) ) gpx - > override [ A ] . active_temperature = atoi ( value ) ;
else if ( PROPERTY_IS ( " standby_temperature " ) ) gpx - > override [ A ] . standby_temperature = atoi ( value ) ;
else if ( PROPERTY_IS ( " build_platform_temperature " ) ) gpx - > override [ A ] . build_platform_temperature = atoi ( value ) ;
else if ( PROPERTY_IS ( " actual_filament_diameter " ) ) gpx - > override [ A ] . actual_filament_diameter = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " packing_density " ) ) gpx - > override [ A ] . packing_density = strtod ( value , NULL ) ;
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " b " ) ) {
if ( PROPERTY_IS ( " max_feedrate " ) ) gpx - > machine . b . max_feedrate = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " steps_per_mm " ) ) gpx - > machine . b . steps_per_mm = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " motor_steps " ) ) gpx - > machine . b . motor_steps = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " has_heated_build_platform " ) ) gpx - > machine . b . has_heated_build_platform = atoi ( value ) ;
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " left " ) ) {
if ( PROPERTY_IS ( " active_temperature " )
| | PROPERTY_IS ( " nozzle_temperature " ) ) gpx - > override [ B ] . active_temperature = atoi ( value ) ;
else if ( PROPERTY_IS ( " standby_temperature " ) ) gpx - > override [ B ] . standby_temperature = atoi ( value ) ;
else if ( PROPERTY_IS ( " build_platform_temperature " ) ) gpx - > override [ B ] . build_platform_temperature = atoi ( value ) ;
else if ( PROPERTY_IS ( " actual_filament_diameter " ) ) gpx - > override [ B ] . actual_filament_diameter = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " packing_density " ) ) gpx - > override [ B ] . packing_density = strtod ( value , NULL ) ;
else goto SECTION_ERROR ;
}
else if ( SECTION_IS ( " machine " ) ) {
if ( PROPERTY_IS ( " nominal_filament_diameter " )
| | PROPERTY_IS ( " slicer_filament_diameter " ) ) gpx - > machine . nominal_filament_diameter = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " packing_density " ) ) gpx - > machine . nominal_packing_density = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " nozzle_diameter " ) ) gpx - > machine . nozzle_diameter = strtod ( value , NULL ) ;
else if ( PROPERTY_IS ( " extruder_count " ) ) gpx - > machine . extruder_count = atoi ( value ) ;
else if ( PROPERTY_IS ( " timeout " ) ) gpx - > machine . timeout = atoi ( value ) ;
else goto SECTION_ERROR ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Configuration error: unrecognised section [%s] " EOL , gpx - > lineNumber , section ) ) ;
return gpx - > lineNumber ;
}
return 0 ;
SECTION_ERROR :
SHOW ( fprintf ( stderr , " (line %u) Configuration error: [%s] section contains unrecognised property %s = %s " EOL , gpx - > lineNumber , section , property , value ) ) ;
return gpx - > lineNumber ;
}
int gpx_read_config ( Gpx * gpx , const char * filename )
{
return ini_parse ( gpx , filename , gpx_set_property ) ;
}
void gpx_register_callback ( Gpx * gpx , int ( * callbackHandler ) ( Gpx * , void * ) , void * callbackData )
{
gpx - > callbackHandler = callbackHandler ;
gpx - > callbackData = callbackData ;
}
void gpx_start_build ( Gpx * gpx , char * buildName )
{
if ( buildName ) gpx - > buildName = buildName ;
if ( gpx - > flag . dittoPrinting & & gpx - > machine . extruder_count = = 1 ) {
SHOW ( fputs ( " Configuration error: ditto printing cannot access non-existant second extruder " EOL , stderr ) ) ;
gpx - > flag . dittoPrinting = 0 ;
}
// CALCULATE FILAMENT SCALING
if ( gpx - > override [ A ] . actual_filament_diameter > 0.0001
& & gpx - > override [ A ] . actual_filament_diameter ! = gpx - > machine . nominal_filament_diameter ) {
set_filament_scale ( gpx , A , gpx - > override [ A ] . actual_filament_diameter ) ;
}
if ( gpx - > override [ B ] . actual_filament_diameter > 0.0001
& & gpx - > override [ B ] . actual_filament_diameter ! = gpx - > machine . nominal_filament_diameter ) {
set_filament_scale ( gpx , B , gpx - > override [ B ] . actual_filament_diameter ) ;
}
}
void gpx_end_build ( Gpx * gpx )
{
if ( gpx - > flag . verboseMode ) {
long seconds = round ( gpx - > accumulated . time ) ;
long minutes = seconds / 60 ;
long hours = minutes / 60 ;
minutes % = 60 ;
seconds % = 60 ;
fprintf ( stderr , " Extrusion length: %#0.3f metres " EOL , round ( gpx - > accumulated . a + gpx - > accumulated . b ) / 1000 ) ;
fputs ( " Estimated print time: " , stderr ) ;
if ( hours ) fprintf ( stderr , " %lu hours " , hours ) ;
if ( minutes ) fprintf ( stderr , " %lu minutes " , minutes ) ;
fprintf ( stderr , " %lu seconds " EOL , seconds ) ;
fprintf ( stderr , " X3G output filesize: %lu bytes " EOL , gpx - > accumulated . bytes ) ;
}
}
int gpx_convert_line ( Gpx * gpx , char * gcode_line )
{
int i , rval ;
int next_line = 0 ;
int command_emitted = 0 ;
// reset flag state
gpx - > command . flag = 0 ;
char * digits ;
char * p = gcode_line ; // current parser location
while ( isspace ( * p ) ) p + + ;
// check for line number
if ( * p = = ' n ' | | * p = = ' N ' ) {
digits = p ;
p = normalize_word ( p ) ;
if ( * p = = 0 ) {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: line number command word 'N' is missing digits " EOL , gpx - > lineNumber ) ) ;
next_line = gpx - > lineNumber + 1 ;
}
else {
next_line = gpx - > lineNumber = atoi ( digits ) ;
}
}
else {
next_line = gpx - > lineNumber + 1 ;
}
// parse command words in command line
while ( * p ! = 0 ) {
if ( isalpha ( * p ) ) {
int c = * p ;
digits = p ;
p = normalize_word ( p ) ;
switch ( c ) {
2013-04-11 05:32:34 +04:00
2013-11-24 17:04:49 +04:00
// PARAMETERS
2013-04-11 05:32:34 +04:00
2013-11-24 17:04:49 +04:00
// Xnnn X coordinate, usually to move to
case ' x ' :
case ' X ' :
gpx - > command . x = strtod ( digits , NULL ) ;
gpx - > command . flag | = X_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
// Ynnn Y coordinate, usually to move to
case ' y ' :
case ' Y ' :
gpx - > command . y = strtod ( digits , NULL ) ;
gpx - > command . flag | = Y_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
// Znnn Z coordinate, usually to move to
case ' z ' :
case ' Z ' :
gpx - > command . z = strtod ( digits , NULL ) ;
gpx - > command . flag | = Z_IS_SET ;
2013-04-17 15:54:52 +04:00
break ;
2013-04-11 05:32:34 +04:00
2013-11-24 17:04:49 +04:00
// Annn Length of extrudate in mm.
case ' a ' :
case ' A ' :
gpx - > command . a = strtod ( digits , NULL ) ;
gpx - > command . flag | = A_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
// Bnnn Length of extrudate in mm.
case ' b ' :
case ' B ' :
gpx - > command . b = strtod ( digits , NULL ) ;
gpx - > command . flag | = B_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
// Ennn Length of extrudate in mm.
case ' e ' :
case ' E ' :
gpx - > command . e = strtod ( digits , NULL ) ;
gpx - > command . flag | = E_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-24 17:04:49 +04:00
// Fnnn Feedrate in mm per minute.
case ' f ' :
case ' F ' :
gpx - > command . f = strtod ( digits , NULL ) ;
gpx - > command . flag | = F_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-24 17:04:49 +04:00
// Pnnn Command parameter, such as a time in milliseconds
case ' p ' :
case ' P ' :
gpx - > command . p = strtod ( digits , NULL ) ;
gpx - > command . flag | = P_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-24 17:04:49 +04:00
// Rnnn Command Parameter, such as RPM
case ' r ' :
case ' R ' :
gpx - > command . r = strtod ( digits , NULL ) ;
gpx - > command . flag | = R_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-24 17:04:49 +04:00
// Snnn Command parameter, such as temperature
case ' s ' :
case ' S ' :
gpx - > command . s = strtod ( digits , NULL ) ;
gpx - > command . flag | = S_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-24 17:04:49 +04:00
// COMMANDS
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
// Gnnn GCode command, such as move to a point
case ' g ' :
case ' G ' :
gpx - > command . g = atoi ( digits ) ;
gpx - > command . flag | = G_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-24 17:04:49 +04:00
// Mnnn RepRap-defined command
case ' m ' :
case ' M ' :
gpx - > command . m = atoi ( digits ) ;
gpx - > command . flag | = M_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
2013-11-24 17:04:49 +04:00
// Tnnn Select extruder nnn.
case ' t ' :
case ' T ' :
gpx - > command . t = atoi ( digits ) ;
gpx - > command . flag | = T_IS_SET ;
2013-04-11 05:32:34 +04:00
break ;
default :
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: unrecognised command word '%c' " EOL , gpx - > lineNumber , c ) ) ;
2013-04-11 05:32:34 +04:00
}
}
2013-11-24 17:04:49 +04:00
else if ( * p = = ' ; ' ) {
if ( * ( p + 1 ) = = ' @ ' ) {
char * s = p + 2 ;
if ( isalpha ( * s ) ) {
char * macro = s ;
// skip any no space characters
while ( * s & & ! isspace ( * s ) ) s + + ;
// null terminate
if ( * s ) * s + + = 0 ;
CALL ( parse_macro ( gpx , macro , normalize_comment ( s ) ) ) ;
* p = 0 ;
break ;
}
}
// Comment
gpx - > command . comment = normalize_comment ( p + 1 ) ;
gpx - > command . flag | = COMMENT_IS_SET ;
* p = 0 ;
break ;
}
else if ( * p = = ' ( ' ) {
if ( * ( p + 1 ) = = ' @ ' ) {
char * s = p + 2 ;
if ( isalpha ( * s ) ) {
char * macro = s ;
char * e = strrchr ( p + 1 , ' ) ' ) ;
// skip any no space characters
while ( * s & & ! isspace ( * s ) ) s + + ;
// null terminate
if ( * s ) * s + + = 0 ;
if ( e ) * e = 0 ;
CALL ( parse_macro ( gpx , macro , normalize_comment ( s ) ) ) ;
* p = 0 ;
break ;
}
}
// Comment
char * s = strchr ( p + 1 , ' ( ' ) ;
char * e = strchr ( p + 1 , ' ) ' ) ;
// check for nested comment
if ( s & & e & & s < e ) {
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: nested comment detected " EOL , gpx - > lineNumber ) ) ;
e = strrchr ( p + 1 , ' ) ' ) ;
}
if ( e ) {
* e = 0 ;
gpx - > command . comment = normalize_comment ( p + 1 ) ;
gpx - > command . flag | = COMMENT_IS_SET ;
p = e + 1 ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: comment is missing closing ')' " EOL , gpx - > lineNumber ) ) ;
gpx - > command . comment = normalize_comment ( p + 1 ) ;
gpx - > command . flag | = COMMENT_IS_SET ;
* p = 0 ;
break ;
}
}
else if ( * p = = ' * ' ) {
// Checksum
* p = 0 ;
break ;
}
else if ( iscntrl ( * p ) ) {
break ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: unrecognised gcode '%s' " EOL , gpx - > lineNumber , p ) ) ;
break ;
}
}
// revert tool selection to current extruder (Makerbot Tn is not sticky)
if ( ! gpx - > flag . reprapFlavor ) gpx - > target . extruder = gpx - > current . extruder ;
// change the extruder selection (in the virtual tool carosel)
if ( gpx - > command . flag & T_IS_SET & & ! gpx - > flag . dittoPrinting ) {
unsigned tool_id = ( unsigned ) gpx - > command . t ;
if ( tool_id < gpx - > machine . extruder_count ) {
gpx - > target . extruder = tool_id ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: T%u cannot select non-existant extruder " EOL , gpx - > lineNumber , tool_id ) ) ;
}
}
// we treat E as short hand for A or B being set, depending on the state of the gpx->current.extruder
if ( gpx - > command . flag & E_IS_SET ) {
if ( gpx - > current . extruder = = 0 ) {
// a = e
gpx - > command . flag | = A_IS_SET ;
gpx - > command . a = gpx - > command . e ;
}
else {
// b = e
gpx - > command . flag | = B_IS_SET ;
gpx - > command . b = gpx - > command . e ;
}
}
// INTERPRET COMMAND
if ( gpx - > command . flag & G_IS_SET ) {
switch ( gpx - > command . g ) {
// G0 - Rapid Positioning
case 0 :
if ( gpx - > command . flag & F_IS_SET ) {
CALL ( calculate_target_position ( gpx ) ) ;
CALL ( queue_ext_point ( gpx , 0.0 ) ) ;
update_current_position ( gpx ) ;
command_emitted + + ;
}
else {
Point3d delta ;
CALL ( calculate_target_position ( gpx ) ) ;
if ( gpx - > command . flag & X_IS_SET ) delta . x = fabs ( gpx - > target . position . x - gpx - > current . position . x ) ;
if ( gpx - > command . flag & Y_IS_SET ) delta . y = fabs ( gpx - > target . position . y - gpx - > current . position . y ) ;
if ( gpx - > command . flag & Z_IS_SET ) delta . z = fabs ( gpx - > target . position . z - gpx - > current . position . z ) ;
double length = magnitude ( gpx - > command . flag & XYZ_BIT_MASK , ( Ptr5d ) & delta ) ;
double candidate , feedrate = DBL_MAX ;
if ( gpx - > command . flag & X_IS_SET & & delta . x ! = 0.0 ) {
feedrate = gpx - > machine . x . max_feedrate * length / delta . x ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & Y_IS_SET & & delta . y ! = 0.0 ) {
candidate = gpx - > machine . y . max_feedrate * length / delta . y ;
if ( feedrate > candidate ) {
feedrate = candidate ;
2013-04-12 17:47:40 +04:00
}
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
if ( gpx - > command . flag & Z_IS_SET & & delta . z ! = 0.0 ) {
candidate = gpx - > machine . z . max_feedrate * length / delta . z ;
if ( feedrate > candidate ) {
feedrate = candidate ;
}
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
if ( feedrate = = DBL_MAX ) {
feedrate = gpx - > machine . x . max_feedrate ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
CALL ( queue_ext_point ( gpx , feedrate ) ) ;
update_current_position ( gpx ) ;
command_emitted + + ;
2013-04-16 20:01:26 +04:00
}
2013-11-24 17:04:49 +04:00
break ;
// G1 - Coordinated Motion
case 1 :
CALL ( calculate_target_position ( gpx ) ) ;
CALL ( queue_ext_point ( gpx , 0.0 ) ) ;
update_current_position ( gpx ) ;
command_emitted + + ;
break ;
// G2 - Clockwise Arc
// G3 - Counter Clockwise Arc
// G4 - Dwell
case 4 :
if ( gpx - > command . flag & P_IS_SET ) {
# if ENABLE_SIMULATED_RPM
if ( gpx - > tool [ gpx - > current . extruder ] . motor_enabled & & gpx - > tool [ gpx - > current . extruder ] . rpm ) {
CALL ( calculate_target_position ( gpx ) ) ;
CALL ( queue_new_point ( gpx , gpx - > command . p ) ) ;
2013-04-21 21:37:12 +04:00
command_emitted + + ;
2013-04-17 20:47:52 +04:00
}
2013-11-24 17:04:49 +04:00
else
# endif
{
CALL ( delay ( gpx , gpx - > command . p ) ) ;
2013-04-21 21:37:12 +04:00
command_emitted + + ;
2013-04-17 20:47:52 +04:00
}
2013-04-11 05:32:34 +04:00
2013-11-24 17:04:49 +04:00
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: G4 is missing delay parameter, use Pn where n is milliseconds " EOL , gpx - > lineNumber ) ) ;
}
break ;
// G10 - Create Coordinate System Offset from the Absolute one
case 10 :
if ( gpx - > command . flag & P_IS_SET & & gpx - > command . p > = 1.0 & & gpx - > command . p < = 6.0 ) {
i = ( int ) gpx - > command . p ;
if ( gpx - > command . flag & X_IS_SET ) gpx - > offset [ i ] . x = gpx - > command . x ;
if ( gpx - > command . flag & Y_IS_SET ) gpx - > offset [ i ] . y = gpx - > command . y ;
if ( gpx - > command . flag & Z_IS_SET ) gpx - > offset [ i ] . z = gpx - > command . z ;
// set standby temperature
if ( gpx - > command . flag & R_IS_SET ) {
unsigned temperature = ( unsigned ) gpx - > command . r ;
if ( temperature > TEMPERATURE_MAX ) temperature = TEMPERATURE_MAX ;
switch ( i ) {
case 1 :
gpx - > override [ A ] . standby_temperature = temperature ;
break ;
case 2 :
gpx - > override [ B ] . standby_temperature = temperature ;
break ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
}
// set tool temperature
if ( gpx - > command . flag & S_IS_SET ) {
unsigned temperature = ( unsigned ) gpx - > command . s ;
if ( temperature > TEMPERATURE_MAX ) temperature = TEMPERATURE_MAX ;
switch ( i ) {
case 1 :
gpx - > override [ A ] . active_temperature = temperature ;
break ;
case 2 :
gpx - > override [ B ] . active_temperature = temperature ;
break ;
2013-04-12 17:47:40 +04:00
}
}
2013-11-24 17:04:49 +04:00
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: G10 is missing coordiante system, use Pn where n is 1-6 " EOL , gpx - > lineNumber ) ) ;
}
break ;
// G21 - Use Milimeters as Units (IGNORED)
// G71 - Use Milimeters as Units (IGNORED)
case 21 :
case 71 :
break ;
// G53 - Set absolute coordinate system
case 53 :
gpx - > current . offset = 0 ;
break ;
// G54 - Use coordinate system from G10 P1
case 54 :
gpx - > current . offset = 1 ;
break ;
// G55 - Use coordinate system from G10 P2
case 55 :
gpx - > current . offset = 2 ;
break ;
// G56 - Use coordinate system from G10 P3
case 56 :
gpx - > current . offset = 3 ;
break ;
// G57 - Use coordinate system from G10 P4
case 57 :
gpx - > current . offset = 4 ;
break ;
// G58 - Use coordinate system from G10 P5
case 58 :
gpx - > current . offset = 5 ;
break ;
// G59 - Use coordinate system from G10 P6
case 59 :
gpx - > current . offset = 6 ;
break ;
// G90 - Absolute Positioning
case 90 :
gpx - > flag . relativeCoordinates = 0 ;
break ;
// G91 - Relative Positioning
case 91 :
if ( gpx - > current . positionKnown ) {
gpx - > flag . relativeCoordinates = 1 ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Semantic error: G91 switch to relitive positioning prior to first absolute move " EOL , gpx - > lineNumber ) ) ;
return - 1 ;
}
break ;
// G92 - Define current position on axes
case 92 : {
if ( gpx - > command . flag & X_IS_SET ) gpx - > current . position . x = gpx - > command . x ;
if ( gpx - > command . flag & Y_IS_SET ) gpx - > current . position . y = gpx - > command . y ;
if ( gpx - > command . flag & Z_IS_SET ) gpx - > current . position . z = gpx - > command . z ;
if ( gpx - > command . flag & A_IS_SET ) gpx - > current . position . a = gpx - > command . a ;
if ( gpx - > command . flag & B_IS_SET ) gpx - > current . position . b = gpx - > command . b ;
CALL ( set_position ( gpx ) ) ;
command_emitted + + ;
// check if we know where we are
int mask = gpx - > machine . extruder_count = = 1 ? ( XYZ_BIT_MASK | A_IS_SET ) : AXES_BIT_MASK ;
if ( ( gpx - > command . flag & mask ) = = mask ) gpx - > current . positionKnown = 1 ;
break ;
}
// G130 - Set given axes potentiometer Value
case 130 :
if ( gpx - > command . flag & X_IS_SET ) {
CALL ( set_pot_value ( gpx , 0 , gpx - > command . x < 0 ? 0 : gpx - > command . x > 127 ? 127 : ( unsigned ) gpx - > command . x ) ) ;
}
if ( gpx - > command . flag & Y_IS_SET ) {
CALL ( set_pot_value ( gpx , 1 , gpx - > command . y < 0 ? 0 : gpx - > command . y > 127 ? 127 : ( unsigned ) gpx - > command . y ) ) ;
}
if ( gpx - > command . flag & Z_IS_SET ) {
CALL ( set_pot_value ( gpx , 2 , gpx - > command . z < 0 ? 0 : gpx - > command . z > 127 ? 127 : ( unsigned ) gpx - > command . z ) ) ;
}
if ( gpx - > command . flag & A_IS_SET ) {
CALL ( set_pot_value ( gpx , 3 , gpx - > command . a < 0 ? 0 : gpx - > command . a > 127 ? 127 : ( unsigned ) gpx - > command . a ) ) ;
}
if ( gpx - > command . flag & B_IS_SET ) {
CALL ( set_pot_value ( gpx , 4 , gpx - > command . b < 0 ? 0 : gpx - > command . b > 127 ? 127 : ( unsigned ) gpx - > command . b ) ) ;
}
break ;
// G161 - Home given axes to minimum
case 161 :
if ( gpx - > command . flag & F_IS_SET ) gpx - > current . feedrate = gpx - > command . f ;
CALL ( home_axes ( gpx , ENDSTOP_IS_MIN ) ) ;
command_emitted + + ;
gpx - > current . positionKnown = 0 ;
gpx - > excess . a = 0 ;
gpx - > excess . b = 0 ;
break ;
// G28 - Home given axes to maximum
// G162 - Home given axes to maximum
case 28 :
case 162 :
if ( gpx - > command . flag & F_IS_SET ) gpx - > current . feedrate = gpx - > command . f ;
CALL ( home_axes ( gpx , ENDSTOP_IS_MAX ) ) ;
command_emitted + + ;
gpx - > current . positionKnown = 0 ;
gpx - > excess . a = 0 ;
gpx - > excess . b = 0 ;
break ;
default :
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: unsupported gcode command 'G%u' " EOL , gpx - > lineNumber , gpx - > command . g ) ) ;
}
}
else if ( gpx - > command . flag & M_IS_SET ) {
switch ( gpx - > command . m ) {
// M2 - End program
case 2 :
if ( program_is_running ( ) ) {
end_program ( ) ;
CALL ( set_build_progress ( gpx , 100 ) ) ;
CALL ( end_build ( gpx ) ) ;
}
return 1 ;
// M6 - Tool change (AND)
// M116 - Wait for extruder AND build platfrom to reach (or exceed) temperature
case 6 :
case 116 : {
int timeout = gpx - > command . flag & P_IS_SET ? ( int ) gpx - > command . p : 0xFFFF ;
if ( ! gpx - > flag . dittoPrinting & &
# if !ENABLE_TOOL_CHANGE_ON_WAIT
gpx - > command . m ! = 116 & &
# endif
gpx - > target . extruder ! = gpx - > current . extruder ) {
CALL ( do_tool_change ( gpx , timeout ) ) ;
command_emitted + + ;
}
// wait for heated build platform
if ( gpx - > machine . a . has_heated_build_platform & & gpx - > tool [ A ] . build_platform_temperature > 0 ) {
CALL ( wait_for_build_platform ( gpx , A , timeout ) ) ;
command_emitted + + ;
}
else if ( gpx - > machine . b . has_heated_build_platform & & gpx - > tool [ B ] . build_platform_temperature > 0 ) {
CALL ( wait_for_build_platform ( gpx , B , timeout ) ) ;
command_emitted + + ;
}
// wait for extruder
if ( gpx - > flag . dittoPrinting ) {
if ( gpx - > tool [ B ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , B , timeout ) ) ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ A ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , A , timeout ) ) ;
}
command_emitted + + ;
}
else {
if ( gpx - > tool [ gpx - > target . extruder ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , gpx - > target . extruder , timeout ) ) ;
command_emitted + + ;
}
}
if ( gpx - > flag . verboseMode ) {
CALL ( display_message ( gpx , " GPX " GPX_VERSION , 0 , 0 , 0 , 0 ) ) ;
CALL ( display_message ( gpx , " by Dr Henry Thomas " , 1 , 0 , 1 , 0 ) ) ;
}
break ;
}
// M17 - Enable axes steppers
case 17 :
if ( gpx - > command . flag & AXES_BIT_MASK ) {
CALL ( set_steppers ( gpx , gpx - > command . flag & AXES_BIT_MASK , 1 ) ) ;
command_emitted + + ;
if ( gpx - > command . flag & A_IS_SET ) gpx - > tool [ A ] . motor_enabled = 1 ;
if ( gpx - > command . flag & B_IS_SET ) gpx - > tool [ B ] . motor_enabled = 1 ;
}
else {
CALL ( set_steppers ( gpx , gpx - > machine . extruder_count = = 1 ? ( XYZ_BIT_MASK | A_IS_SET ) : AXES_BIT_MASK , 1 ) ) ;
command_emitted + + ;
gpx - > tool [ A ] . motor_enabled = 1 ;
if ( gpx - > machine . extruder_count = = 2 ) gpx - > tool [ B ] . motor_enabled = 1 ;
}
break ;
// M18 - Disable axes steppers
case 18 :
if ( gpx - > command . flag & AXES_BIT_MASK ) {
CALL ( set_steppers ( gpx , gpx - > command . flag & AXES_BIT_MASK , 0 ) ) ;
command_emitted + + ;
if ( gpx - > command . flag & A_IS_SET ) gpx - > tool [ A ] . motor_enabled = 0 ;
if ( gpx - > command . flag & B_IS_SET ) gpx - > tool [ B ] . motor_enabled = 0 ;
}
else {
CALL ( set_steppers ( gpx , gpx - > machine . extruder_count = = 1 ? ( XYZ_BIT_MASK | A_IS_SET ) : AXES_BIT_MASK , 0 ) ) ;
command_emitted + + ;
gpx - > tool [ A ] . motor_enabled = 0 ;
if ( gpx - > machine . extruder_count = = 2 ) gpx - > tool [ B ] . motor_enabled = 0 ;
}
break ;
// M70 - Display message on LCD
case 70 :
if ( gpx - > command . flag & COMMENT_IS_SET ) {
unsigned vPos = gpx - > command . flag & Y_IS_SET ? ( unsigned ) gpx - > command . y : 0 ;
2013-04-21 21:37:12 +04:00
if ( vPos > 3 ) vPos = 3 ;
2013-11-24 17:04:49 +04:00
unsigned hPos = gpx - > command . flag & X_IS_SET ? ( unsigned ) gpx - > command . x : 0 ;
2013-04-21 21:37:12 +04:00
if ( hPos > 19 ) hPos = 19 ;
2013-11-24 17:04:49 +04:00
int timeout = gpx - > command . flag & P_IS_SET ? gpx - > command . p : 0 ;
CALL ( display_message ( gpx , gpx - > command . comment , vPos , hPos , timeout , 0 ) ) ;
command_emitted + + ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: M70 is missing message text, use (text) where text is message " EOL , gpx - > lineNumber ) ) ;
}
break ;
// M71 - Display message and wait for button press
case 71 : {
char * message = gpx - > command . flag & COMMENT_IS_SET ? gpx - > command . comment : " Press M to continue " ;
unsigned vPos = gpx - > command . flag & Y_IS_SET ? ( unsigned ) gpx - > command . y : 0 ;
if ( vPos > 3 ) vPos = 3 ;
unsigned hPos = gpx - > command . flag & X_IS_SET ? ( unsigned ) gpx - > command . x : 0 ;
if ( hPos > 19 ) hPos = 19 ;
int timeout = gpx - > command . flag & P_IS_SET ? gpx - > command . p : 0 ;
CALL ( display_message ( gpx , message , vPos , hPos , timeout , 1 ) ) ;
command_emitted + + ;
break ;
}
// M72 - Queue a song or play a tone
case 72 :
if ( gpx - > command . flag & P_IS_SET ) {
unsigned song_id = ( unsigned ) gpx - > command . p ;
if ( song_id > 2 ) song_id = 2 ;
CALL ( queue_song ( gpx , song_id ) ) ;
command_emitted + + ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: M72 is missing song number, use Pn where n is 0-2 " EOL , gpx - > lineNumber ) ) ;
}
break ;
// M73 - Manual set build percentage
case 73 :
if ( gpx - > command . flag & P_IS_SET ) {
unsigned percent = ( unsigned ) gpx - > command . p ;
if ( percent > 100 ) percent = 100 ;
if ( program_is_ready ( ) ) {
start_program ( ) ;
CALL ( start_build ( gpx , gpx - > buildName ) ) ;
CALL ( set_build_progress ( gpx , 0 ) ) ;
// start extruder in a known state
CALL ( change_extruder_offset ( gpx , gpx - > current . extruder ) ) ;
}
else if ( program_is_running ( ) ) {
if ( percent = = 100 ) {
// disable macros in footer
gpx - > flag . macrosEnabled = 0 ;
end_program ( ) ;
CALL ( set_build_progress ( gpx , 100 ) ) ;
CALL ( end_build ( gpx ) ) ;
gpx - > current . percent = 100 ;
2013-04-12 17:47:40 +04:00
}
else {
2013-11-24 17:04:49 +04:00
// enable macros in object body
if ( ! gpx - > flag . macrosEnabled & & percent > 0 ) {
if ( gpx - > flag . pausePending ) {
CALL ( pause_at_zpos ( gpx , gpx - > commandAt [ 0 ] . z ) ) ;
gpx - > flag . pausePending = 0 ;
}
gpx - > flag . macrosEnabled = 1 ;
}
if ( percent & & ( gpx - > total . time = = 0.0 | | gpx - > flag . buildProgress = = 0 ) ) {
CALL ( set_build_progress ( gpx , percent ) ) ;
gpx - > current . percent = percent ;
}
2013-04-12 17:47:40 +04:00
}
}
2013-11-24 17:04:49 +04:00
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: M73 is missing build percentage, use Pn where n is 0-100 " EOL , gpx - > lineNumber ) ) ;
}
break ;
// M82 - set extruder to absolute mode
case 82 :
gpx - > flag . extruderIsRelative = 0 ;
break ;
// M83 - set extruder to relative mode
case 83 :
gpx - > flag . extruderIsRelative = 1 ;
break ;
// M84 - Stop idle hold
case 84 :
CALL ( set_steppers ( gpx , gpx - > machine . extruder_count = = 1 ? ( XYZ_BIT_MASK | A_IS_SET ) : AXES_BIT_MASK , 0 ) ) ;
command_emitted + + ;
gpx - > tool [ A ] . motor_enabled = 0 ;
if ( gpx - > machine . extruder_count = = 2 ) gpx - > tool [ B ] . motor_enabled = 0 ;
break ;
// M101 - Turn extruder on, forward
// M102 - Turn extruder on, reverse
case 101 :
case 102 :
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_steppers ( gpx , A_IS_SET | B_IS_SET , 1 ) ) ;
command_emitted + + ;
gpx - > tool [ A ] . motor_enabled = gpx - > tool [ B ] . motor_enabled = gpx - > command . m = = 101 ? 1 : - 1 ;
}
else {
CALL ( set_steppers ( gpx , gpx - > target . extruder = = 0 ? A_IS_SET : B_IS_SET , 1 ) ) ;
command_emitted + + ;
gpx - > tool [ gpx - > target . extruder ] . motor_enabled = gpx - > command . m = = 101 ? 1 : - 1 ;
}
break ;
// M103 - Turn extruder off
case 103 :
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_steppers ( gpx , A_IS_SET | B_IS_SET , 1 ) ) ;
command_emitted + + ;
gpx - > tool [ A ] . motor_enabled = gpx - > tool [ B ] . motor_enabled = 0 ;
}
else {
CALL ( set_steppers ( gpx , gpx - > target . extruder = = 0 ? A_IS_SET : B_IS_SET , 0 ) ) ;
command_emitted + + ;
gpx - > tool [ gpx - > target . extruder ] . motor_enabled = 0 ;
}
break ;
// M104 - Set extruder temperature
case 104 :
if ( gpx - > command . flag & S_IS_SET ) {
unsigned temperature = ( unsigned ) gpx - > command . s ;
if ( temperature > TEMPERATURE_MAX ) temperature = TEMPERATURE_MAX ;
if ( gpx - > flag . dittoPrinting ) {
if ( temperature & & gpx - > override [ gpx - > current . extruder ] . active_temperature ) {
temperature = gpx - > override [ gpx - > current . extruder ] . active_temperature ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
CALL ( set_nozzle_temperature ( gpx , B , temperature ) ) ;
CALL ( set_nozzle_temperature ( gpx , A , temperature ) ) ;
command_emitted + + ;
gpx - > tool [ A ] . nozzle_temperature = gpx - > tool [ B ] . nozzle_temperature = temperature ;
}
else {
if ( temperature & & gpx - > override [ gpx - > target . extruder ] . active_temperature ) {
temperature = gpx - > override [ gpx - > target . extruder ] . active_temperature ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
CALL ( set_nozzle_temperature ( gpx , gpx - > target . extruder , temperature ) ) ;
command_emitted + + ;
gpx - > tool [ gpx - > target . extruder ] . nozzle_temperature = temperature ;
2013-04-12 17:47:40 +04:00
}
2013-04-21 21:37:12 +04:00
}
2013-11-24 17:04:49 +04:00
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: M104 is missing temperature, use Sn where n is 0-280 " EOL , gpx - > lineNumber ) ) ;
}
break ;
// M106 - Turn cooling fan on
case 106 : {
int state = ( gpx - > command . flag & S_IS_SET ) ? ( ( unsigned ) gpx - > command . s ? 1 : 0 ) : 1 ;
if ( gpx - > flag . reprapFlavor & & gpx - > machine . type > = MACHINE_TYPE_REPLICATOR_1 ) {
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_valve ( gpx , B , state ) ) ;
CALL ( set_valve ( gpx , A , state ) ) ;
2013-04-21 21:37:12 +04:00
command_emitted + + ;
2013-04-12 17:47:40 +04:00
}
else {
2013-11-24 17:04:49 +04:00
CALL ( set_valve ( gpx , gpx - > target . extruder , state ) ) ;
command_emitted + + ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
}
else {
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_fan ( gpx , B , state ) ) ;
CALL ( set_fan ( gpx , A , state ) ) ;
command_emitted + + ;
2013-04-12 17:47:40 +04:00
}
else {
2013-11-24 17:04:49 +04:00
CALL ( set_fan ( gpx , gpx - > target . extruder , state ) ) ;
command_emitted + + ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
}
break ;
}
// M107 - Turn cooling fan off
case 107 :
if ( gpx - > flag . reprapFlavor & & gpx - > machine . type > = MACHINE_TYPE_REPLICATOR_1 ) {
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_valve ( gpx , B , 0 ) ) ;
CALL ( set_valve ( gpx , A , 0 ) ) ;
2013-04-22 18:22:44 +04:00
command_emitted + + ;
}
2013-04-12 17:47:40 +04:00
else {
2013-11-24 17:04:49 +04:00
CALL ( set_valve ( gpx , gpx - > target . extruder , 0 ) ) ;
2013-04-21 21:37:12 +04:00
command_emitted + + ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
}
else {
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_fan ( gpx , B , 0 ) ) ;
CALL ( set_fan ( gpx , A , 0 ) ) ;
2013-04-22 18:22:44 +04:00
command_emitted + + ;
}
2013-04-12 17:47:40 +04:00
else {
2013-11-24 17:04:49 +04:00
CALL ( set_fan ( gpx , gpx - > target . extruder , 0 ) ) ;
2013-04-21 21:37:12 +04:00
command_emitted + + ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
}
break ;
// M108 - set extruder motor 5D 'simulated' RPM
case 108 :
# if ENABLE_SIMULATED_RPM
if ( gpx - > command . flag & R_IS_SET ) {
if ( gpx - > flag . dittoPrinting ) {
gpx - > tool [ A ] . rpm = gpx - > tool [ B ] . rpm = gpx - > command . r ;
}
else {
gpx - > tool [ gpx - > target . extruder ] . rpm = gpx - > command . r ;
}
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: M108 is missing motor RPM, use Rn where n is 0-5 " EOL , gpx - > lineNumber ) ) ;
}
# endif
break ;
// M109 - Set Extruder Temperature and Wait
case 109 :
if ( gpx - > flag . reprapFlavor ) {
if ( gpx - > command . flag & S_IS_SET ) {
int timeout = gpx - > command . flag & P_IS_SET ? ( int ) gpx - > command . p : 0xFFFF ;
unsigned temperature = ( unsigned ) gpx - > command . s ;
2013-05-17 04:59:01 +04:00
if ( temperature > TEMPERATURE_MAX ) temperature = TEMPERATURE_MAX ;
2013-11-24 17:04:49 +04:00
if ( gpx - > flag . dittoPrinting ) {
unsigned tempB = temperature ;
// set extruder temperatures
if ( temperature ) {
if ( gpx - > override [ B ] . active_temperature ) {
tempB = gpx - > override [ B ] . active_temperature ;
}
if ( gpx - > override [ A ] . active_temperature ) {
temperature = gpx - > override [ A ] . active_temperature ;
}
}
CALL ( set_nozzle_temperature ( gpx , B , tempB ) ) ;
CALL ( set_nozzle_temperature ( gpx , A , temperature ) ) ;
gpx - > tool [ B ] . nozzle_temperature = tempB ;
gpx - > tool [ A ] . nozzle_temperature = temperature ;
// wait for extruders to reach (or exceed) temperature
if ( gpx - > tool [ B ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , B , timeout ) ) ;
}
if ( gpx - > tool [ A ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , A , timeout ) ) ;
2013-04-22 18:22:44 +04:00
}
command_emitted + + ;
}
2013-04-12 17:47:40 +04:00
else {
2013-11-24 17:04:49 +04:00
# if ENABLE_TOOL_CHANGE_ON_WAIT
// because there is a wait we do a tool change
if ( gpx - > target . extruder ! = gpx - > current . extruder ) {
CALL ( do_tool_change ( gpx , timeout ) ) ;
}
# endif
// set extruder temperature
if ( temperature & & gpx - > override [ gpx - > target . extruder ] . active_temperature ) {
temperature = gpx - > override [ gpx - > target . extruder ] . active_temperature ;
}
CALL ( set_nozzle_temperature ( gpx , gpx - > target . extruder , temperature ) ) ;
gpx - > tool [ gpx - > target . extruder ] . nozzle_temperature = temperature ;
// wait for extruder to reach (or exceed) temperature
if ( gpx - > tool [ gpx - > target . extruder ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , gpx - > target . extruder , timeout ) ) ;
2013-04-18 19:01:37 +04:00
}
2013-04-21 21:37:12 +04:00
command_emitted + + ;
2013-04-12 17:47:40 +04:00
}
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Syntax error: M109 is missing temperature, use Sn where n is 0-280 " EOL , gpx - > lineNumber ) ) ;
2013-04-12 17:47:40 +04:00
}
break ;
2013-11-24 17:04:49 +04:00
}
// fall through to M140 for Makerbot/ReplicatorG flavor
// M140 - Set Build Platform Temperature
case 140 :
if ( gpx - > machine . a . has_heated_build_platform | | gpx - > machine . b . has_heated_build_platform ) {
if ( gpx - > command . flag & S_IS_SET ) {
unsigned temperature = ( unsigned ) gpx - > command . s ;
if ( temperature > HBP_MAX ) temperature = HBP_MAX ;
unsigned tool_id = gpx - > machine . a . has_heated_build_platform ? A : B ;
if ( gpx - > command . flag & T_IS_SET ) {
tool_id = gpx - > target . extruder ;
}
if ( tool_id ? gpx - > machine . b . has_heated_build_platform : gpx - > machine . a . has_heated_build_platform ) {
if ( temperature & & gpx - > override [ tool_id ] . build_platform_temperature ) {
temperature = gpx - > override [ tool_id ] . build_platform_temperature ;
}
CALL ( set_build_platform_temperature ( gpx , tool_id , temperature ) ) ;
2013-09-25 22:06:43 +04:00
command_emitted + + ;
2013-11-24 17:04:49 +04:00
gpx - > tool [ tool_id ] . build_platform_temperature = temperature ;
2013-09-25 22:06:43 +04:00
}
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: M%u cannot select non-existant heated build platform T%u " EOL , gpx - > lineNumber , gpx - > command . m , tool_id ) ) ;
2013-09-25 22:06:43 +04:00
}
2013-04-22 18:22:44 +04:00
}
2013-04-12 17:47:40 +04:00
else {
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Syntax error: M%u is missing temperature, use Sn where n is 0-120 " EOL , gpx - > lineNumber , gpx - > command . m ) ) ;
2013-04-12 17:47:40 +04:00
}
2013-05-03 17:57:14 +04:00
}
2013-11-24 17:04:49 +04:00
else {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: M%u cannot select non-existant heated build platform " EOL , gpx - > lineNumber , gpx - > command . m ) ) ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
break ;
// M126 - Turn blower fan on (valve open)
case 126 : {
int state = ( gpx - > command . flag & S_IS_SET ) ? ( ( unsigned ) gpx - > command . s ? 1 : 0 ) : 1 ;
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_valve ( gpx , B , state ) ) ;
CALL ( set_valve ( gpx , A , state ) ) ;
2013-11-15 21:17:33 +04:00
command_emitted + + ;
}
2013-11-24 17:04:49 +04:00
else {
CALL ( set_valve ( gpx , gpx - > target . extruder , state ) ) ;
2013-11-15 21:17:33 +04:00
command_emitted + + ;
}
2013-11-24 17:04:49 +04:00
break ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
// M127 - Turn blower fan off (valve close)
case 127 :
if ( gpx - > flag . dittoPrinting ) {
CALL ( set_valve ( gpx , B , 0 ) ) ;
CALL ( set_valve ( gpx , A , 0 ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
else {
CALL ( set_valve ( gpx , gpx - > target . extruder , 0 ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
}
break ;
2013-11-24 17:04:49 +04:00
// M131 - Store Current Position to EEPROM
case 131 :
if ( gpx - > command . flag & AXES_BIT_MASK ) {
CALL ( store_home_positions ( gpx ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: M131 is missing axes, use X Y Z A B " EOL , gpx - > lineNumber ) ) ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
break ;
// M132 - Load Current Position from EEPROM
case 132 :
if ( gpx - > command . flag & AXES_BIT_MASK ) {
CALL ( recall_home_positions ( gpx ) ) ;
command_emitted + + ;
gpx - > current . positionKnown = 0 ;
gpx - > excess . a = 0 ;
gpx - > excess . b = 0 ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax error: M132 is missing axes, use X Y Z A B " EOL , gpx - > lineNumber ) ) ;
2013-08-22 15:48:32 +04:00
}
2013-11-24 17:04:49 +04:00
break ;
// M133 - Wait for extruder
case 133 : {
int timeout = gpx - > command . flag & P_IS_SET ? ( int ) gpx - > command . p : 0xFFFF ;
// changing the
if ( gpx - > flag . dittoPrinting ) {
if ( gpx - > tool [ B ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , B , timeout ) ) ;
2013-05-03 17:57:14 +04:00
}
2013-11-24 17:04:49 +04:00
if ( gpx - > tool [ A ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , A , timeout ) ) ;
2013-05-03 17:57:14 +04:00
}
2013-11-24 17:04:49 +04:00
command_emitted + + ;
2013-05-03 17:57:14 +04:00
}
2013-11-24 17:04:49 +04:00
else {
# if ENABLE_TOOL_CHANGE_ON_WAIT
// because there is a wait we do a tool change
if ( gpx - > target . extruder ! = gpx - > current . extruder ) {
CALL ( do_tool_change ( gpx , timeout ) ) ;
2013-08-22 15:48:32 +04:00
}
2013-11-24 17:04:49 +04:00
# endif
// any tool changes have already occured
if ( gpx - > tool [ gpx - > target . extruder ] . nozzle_temperature > 0 ) {
CALL ( wait_for_extruder ( gpx , gpx - > target . extruder , timeout ) ) ;
2013-08-22 15:48:32 +04:00
}
2013-11-24 17:04:49 +04:00
command_emitted + + ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
break ;
}
// M134
// M190 - Wait for build platform to reach (or exceed) temperature
case 134 :
case 190 : {
if ( gpx - > machine . a . has_heated_build_platform | | gpx - > machine . b . has_heated_build_platform ) {
int timeout = gpx - > command . flag & P_IS_SET ? ( int ) gpx - > command . p : 0xFFFF ;
unsigned tool_id = gpx - > machine . a . has_heated_build_platform ? A : B ;
if ( gpx - > command . flag & T_IS_SET ) {
tool_id = gpx - > target . extruder ;
2013-08-22 15:48:32 +04:00
}
2013-11-24 17:04:49 +04:00
if ( tool_id ? gpx - > machine . b . has_heated_build_platform : gpx - > machine . a . has_heated_build_platform
& & gpx - > tool [ tool_id ] . build_platform_temperature > 0 ) {
CALL ( wait_for_build_platform ( gpx , tool_id , timeout ) ) ;
command_emitted + + ;
2013-04-19 08:53:34 +04:00
}
2013-11-24 17:04:49 +04:00
else {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: M%u cannot select non-existant heated build platform T%u " EOL , gpx - > lineNumber , gpx - > command . m , tool_id ) ) ;
2013-04-19 08:53:34 +04:00
}
2013-04-22 18:22:44 +04:00
}
2013-11-24 17:04:49 +04:00
else {
SHOW ( fprintf ( stderr , " (line %u) Semantic warning: M%u cannot select non-existant heated build platform " EOL , gpx - > lineNumber , gpx - > command . m ) ) ;
2013-11-15 21:17:33 +04:00
}
break ;
2013-11-24 17:04:49 +04:00
}
// M135 - Change tool
case 135 :
if ( ! gpx - > flag . dittoPrinting & & gpx - > target . extruder ! = gpx - > current . extruder ) {
int timeout = gpx - > command . flag & P_IS_SET ? ( int ) gpx - > command . p : 0xFFFF ;
CALL ( do_tool_change ( gpx , timeout ) ) ;
command_emitted + + ;
}
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
// M136 - Build start notification
case 136 :
if ( program_is_ready ( ) ) {
start_program ( ) ;
CALL ( start_build ( gpx , gpx - > buildName ) ) ;
CALL ( set_build_progress ( gpx , 0 ) ) ;
// start extruder in a known state
CALL ( change_extruder_offset ( gpx , gpx - > current . extruder ) ) ;
}
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
// M137 - Build end notification
case 137 :
if ( program_is_running ( ) ) {
end_program ( ) ;
CALL ( set_build_progress ( gpx , 100 ) ) ;
CALL ( end_build ( gpx ) ) ;
gpx - > current . percent = 100 ;
}
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
// M300 - Set Beep (SP)
case 300 : {
unsigned frequency = 300 ;
if ( gpx - > command . flag & S_IS_SET ) frequency = ( unsigned ) gpx - > command . s & 0xFFFF ;
unsigned milliseconds = 1000 ;
if ( gpx - > command . flag & P_IS_SET ) milliseconds = ( unsigned ) gpx - > command . p & 0xFFFF ;
CALL ( set_beep ( gpx , frequency , milliseconds ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
}
// M320 - Acceleration on for subsequent instructions
case 320 :
CALL ( set_acceleration ( gpx , 1 ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
// M321 - Acceleration off for subsequent instructions
case 321 :
CALL ( set_acceleration ( gpx , 0 ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
// M322 - Pause @ zPos
case 322 :
if ( gpx - > command . flag & Z_IS_SET ) {
float conditional_z = gpx - > offset [ gpx - > current . offset ] . z ;
if ( gpx - > flag . macrosEnabled ) {
conditional_z + = gpx - > userOffset . z ;
}
double z = gpx - > flag . relativeCoordinates ? ( gpx - > current . position . z + gpx - > command . z ) : ( gpx - > command . z + conditional_z ) ;
CALL ( pause_at_zpos ( gpx , z ) ) ;
}
else {
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: M322 is missing Z axis " EOL , gpx - > lineNumber ) ) ;
}
command_emitted + + ;
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
// M420 - Set RGB LED value (REB - P)
case 420 : {
unsigned red = 0 ;
if ( gpx - > command . flag & R_IS_SET ) red = ( unsigned ) gpx - > command . r & 0xFF ;
unsigned green = 0 ;
if ( gpx - > command . flag & E_IS_SET ) green = ( unsigned ) gpx - > command . e & 0xFF ;
unsigned blue = 0 ;
if ( gpx - > command . flag & B_IS_SET ) blue = ( unsigned ) gpx - > command . b & 0xFF ;
unsigned blink = 0 ;
if ( gpx - > command . flag & P_IS_SET ) blink = ( unsigned ) gpx - > command . p & 0xFF ;
CALL ( set_LED ( gpx , red , green , blue , blink ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
break ;
2013-11-24 17:04:49 +04:00
}
2013-11-15 21:17:33 +04:00
default :
2013-11-24 17:04:49 +04:00
SHOW ( fprintf ( stderr , " (line %u) Syntax warning: unsupported mcode command 'M%u' " EOL , gpx - > lineNumber , gpx - > command . m ) ) ;
2013-11-15 21:17:33 +04:00
}
}
2013-11-24 17:04:49 +04:00
else {
// X,Y,Z,A,B,E,F
if ( gpx - > command . flag & ( AXES_BIT_MASK | F_IS_SET ) ) {
CALL ( calculate_target_position ( gpx ) ) ;
CALL ( queue_ext_point ( gpx , 0.0 ) ) ;
update_current_position ( gpx ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
// Tn
else if ( ! gpx - > flag . dittoPrinting & & gpx - > target . extruder ! = gpx - > current . extruder ) {
int timeout = gpx - > command . flag & P_IS_SET ? ( int ) gpx - > command . p : 0xFFFF ;
CALL ( do_tool_change ( gpx , timeout ) ) ;
command_emitted + + ;
2013-11-15 21:17:33 +04:00
}
}
2013-11-24 17:04:49 +04:00
// check for pending pause @ zPos
if ( gpx - > flag . doPauseAtZPos ) {
gpx - > flag . doPauseAtZPos - - ;
// issue next pause @ zPos after command buffer is flushed
if ( gpx - > flag . doPauseAtZPos = = 0 ) {
CALL ( pause_at_zpos ( gpx , gpx - > commandAt [ gpx - > commandAtIndex ] . z ) ) ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
}
// update progress
if ( gpx - > total . time > 0.0001 & & gpx - > accumulated . time > 0.0001 & & gpx - > flag . buildProgress & & command_emitted ) {
unsigned percent = ( unsigned ) round ( 100.0 * gpx - > accumulated . time / gpx - > total . time ) ;
if ( percent > gpx - > current . percent ) {
if ( program_is_ready ( ) ) {
start_program ( ) ;
CALL ( start_build ( gpx , gpx - > buildName ) ) ;
CALL ( set_build_progress ( gpx , 0 ) ) ;
// start extruder in a known state
CALL ( change_extruder_offset ( gpx , gpx - > current . extruder ) ) ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
else if ( percent < 100 & & program_is_running ( ) ) {
CALL ( set_build_progress ( gpx , percent ) ) ;
gpx - > current . percent = percent ;
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
command_emitted = 0 ;
2013-04-11 05:32:34 +04:00
}
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
gpx - > lineNumber = next_line ;
return 0 ;
}
typedef struct tFile {
FILE * in ;
FILE * out ;
FILE * out2 ;
} File ;
static int file_handler ( Gpx * gpx , File * file )
{
size_t bytes , length = gpx - > buffer . ptr - gpx - > buffer . out ;
if ( length ) {
bytes = fwrite ( gpx - > buffer . out , 1 , length , file - > out ) ;
if ( bytes ! = length ) return - 1 ;
if ( file - > out2 ) {
bytes = fwrite ( gpx - > buffer . out , 1 , length , file - > out2 ) ;
if ( bytes ! = length ) return - 1 ;
}
2013-04-12 17:47:40 +04:00
}
2013-11-24 17:04:49 +04:00
return 0 ;
}
int gpx_convert_file ( Gpx * gpx , FILE * file_in , FILE * file_out , FILE * file_out2 )
{
int i , rval ;
File file ;
file . in = stdin ;
file . out = stdout ;
file . out2 = NULL ;
int verboseMode = gpx - > flag . verboseMode ;
int showErrorMessages = gpx - > flag . showErrorMessages ;
if ( file_in & & file_in ! = stdin ) {
// Multi-pass
file . in = file_in ;
i = 0 ;
gpx - > callbackHandler = NULL ;
gpx - > callbackData = NULL ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
else {
// Single-pass
i = 1 ;
gpx - > callbackHandler = ( int ( * ) ( Gpx * , void * ) ) file_handler ; ;
gpx - > callbackData = & file ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
if ( file_out ) {
file . out = file_out ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
file . out2 = file_out2 ;
for ( ; ; ) {
int overflow = 0 ;
while ( fgets ( gpx - > buffer . in , BUFFER_MAX , file . in ) ! = NULL ) {
// detect input buffer overflow and ignore overflow input
if ( overflow ) {
if ( strlen ( gpx - > buffer . in ) ! = BUFFER_MAX - 1 ) {
overflow = 0 ;
}
continue ;
}
if ( strlen ( gpx - > buffer . in ) = = BUFFER_MAX - 1 ) {
overflow = 1 ;
SHOW ( fprintf ( stderr , " (line %u) Buffer overflow: input exceeds %u character limit, remaining characters in line will be ignored " EOL , gpx - > lineNumber , BUFFER_MAX ) ) ;
}
rval = gpx_convert_line ( gpx , gpx - > buffer . in ) ;
// normal exit
if ( rval > 0 ) break ;
// error
if ( rval < 0 ) return rval ;
}
if ( program_is_running ( ) ) {
end_program ( ) ;
CALL ( set_build_progress ( gpx , 100 ) ) ;
CALL ( end_build ( gpx ) ) ;
}
CALL ( set_steppers ( gpx , AXES_BIT_MASK , 0 ) ) ;
gpx - > total . length = gpx - > accumulated . a + gpx - > accumulated . b ;
gpx - > total . time = gpx - > accumulated . time ;
gpx - > total . bytes = gpx - > accumulated . bytes ;
if ( + + i > 1 ) break ;
// rewind for second pass
fseek ( file . in , 0L , SEEK_SET ) ;
gpx_initialize ( gpx , 0 ) ;
gpx - > flag . verboseMode = 0 ;
gpx - > flag . showErrorMessages = 0 ;
gpx - > callbackHandler = ( int ( * ) ( Gpx * , void * ) ) file_handler ;
gpx - > callbackData = & file ;
2013-11-15 21:17:33 +04:00
}
2013-11-24 17:04:49 +04:00
gpx - > flag . verboseMode = verboseMode ; ;
gpx - > flag . showErrorMessages = showErrorMessages ; ;
return 0 ;
}
typedef struct tSio {
FILE * in ;
int port ;
} Sio ;
2013-11-15 21:17:33 +04:00
2013-11-24 17:04:49 +04:00
static int port_handler ( Gpx * gpx , Sio * sio )
{
size_t bytes , length = gpx - > buffer . ptr - gpx - > buffer . out ;
if ( length ) {
// #TODO write serial I/O
}
return 0 ;
2013-04-11 05:32:34 +04:00
}
2013-11-24 17:04:49 +04:00
int gpx_send_file ( Gpx * gpx , FILE * file_in , int sio_port )
{
int i , rval ;
Sio sio ;
sio . in = stdin ;
sio . port = - 1 ;
int verboseMode = gpx - > flag . verboseMode ;
int showErrorMessages = gpx - > flag . showErrorMessages ;
if ( file_in & & file_in ! = stdin ) {
// Multi-pass
sio . in = file_in ;
i = 0 ;
gpx - > flag . framingEnabled = 0 ;
gpx - > callbackHandler = NULL ;
gpx - > callbackData = NULL ;
}
else {
// Single-pass
i = 1 ;
gpx - > flag . framingEnabled = 1 ;
gpx - > callbackHandler = ( int ( * ) ( Gpx * , void * ) ) port_handler ; ;
gpx - > callbackData = & sio ;
}
if ( sio_port > 2 ) {
sio . port = sio_port ;
}
for ( ; ; ) {
int overflow = 0 ;
while ( fgets ( gpx - > buffer . in , BUFFER_MAX , sio . in ) ! = NULL ) {
// detect input buffer overflow and ignore overflow input
if ( overflow ) {
if ( strlen ( gpx - > buffer . in ) ! = BUFFER_MAX - 1 ) {
overflow = 0 ;
}
continue ;
}
if ( strlen ( gpx - > buffer . in ) = = BUFFER_MAX - 1 ) {
overflow = 1 ;
SHOW ( fprintf ( stderr , " (line %u) Buffer overflow: input exceeds %u character limit, remaining characters in line will be ignored " EOL , gpx - > lineNumber , BUFFER_MAX ) ) ;
}
rval = gpx_convert_line ( gpx , gpx - > buffer . in ) ;
// normal exit
if ( rval > 0 ) break ;
// error
if ( rval < 0 ) return rval ;
}
if ( program_is_running ( ) ) {
end_program ( ) ;
CALL ( set_build_progress ( gpx , 100 ) ) ;
CALL ( end_build ( gpx ) ) ;
}
CALL ( set_steppers ( gpx , AXES_BIT_MASK , 0 ) ) ;
gpx - > total . length = gpx - > accumulated . a + gpx - > accumulated . b ;
gpx - > total . time = gpx - > accumulated . time ;
gpx - > total . bytes = gpx - > accumulated . bytes ;
if ( + + i > 1 ) break ;
// rewind for second pass
fseek ( sio . in , 0L , SEEK_SET ) ;
gpx_initialize ( gpx , 0 ) ;
gpx - > flag . verboseMode = 0 ;
gpx - > flag . showErrorMessages = 0 ;
gpx - > flag . framingEnabled = 1 ;
gpx - > callbackHandler = ( int ( * ) ( Gpx * , void * ) ) port_handler ; ;
gpx - > callbackData = & sio ;
}
gpx - > flag . verboseMode = verboseMode ; ;
gpx - > flag . showErrorMessages = showErrorMessages ; ;
return 0 ;
}