Alpha 0.1

All suppoted G and M codes are now implemented, and the output from the
lint.gcode unit test has been compared to that of ReplicatorG to
confirm equivilance.
master
WHPThomas 2013-04-17 21:54:52 +10:00
parent 17d5cbd2c7
commit cc5b5aa561
6 changed files with 722 additions and 155 deletions

138
getopt.c Executable file
View File

@ -0,0 +1,138 @@
/*
Newsgroups: mod.std.unix
Subject: public domain AT&T getopt source
Date: 3 Nov 85 19:34:15 GMT
Here's something you've all been waiting for: the AT&T public domain
source for getopt(3). It is the code which was given out at the 1985
UNIFORUM conference in Dallas. I obtained it by electronic mail
directly from AT&T. The people there assure me that it is indeed
in the public domain.
25/1/2005 Henry Thomas <me(at)henri.net>
Ported this original AT&T version of 'getopt' to windows.
Added 'getargv' to parse the 'WinMain' 'lpCmdLine' argument and convert it
into an argc/argv pair. This should improve portability between windows and
unix/linux platforms.
*/
#include "321/getopt.h"
#ifndef HAS_GETOPT_H
#include <string.h>
#if defined(_MSC_VER)
# include <io.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef HAS_WIN_GUI
/* The windows gui version reports command line errors using MessageBox */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ERR(s, c) if(opterr) {\
char buffer[64];\
_snprintf(buffer, 64, "%s%s%c", argv[0], s, c);\
MessageBox(NULL, buffer, "Command Line Error", MB_OK | MB_ICONERROR);\
}
#else
#define ERR(s, c) if(opterr) {\
char errbuf[2];\
errbuf[0] = c; errbuf[1] = '\n';\
(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
(void) write(2, s, (unsigned)strlen(s));\
(void) write(2, errbuf, 2);\
}
#endif
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int getopt(int argc, char **argv, char *opts)
{
static int sp = 1;
register int c;
register char *cp;
if(sp == 1) {
if(optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0') {
return(-1);
}
else if(strcmp(argv[optind], "--") == 0) {
optind++;
return(-1);
}
}
optopt = c = argv[optind][sp];
if(c == ':' || (cp = strchr(opts, c)) == NULL) {
ERR(": illegal option -- ", c);
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return('?');
}
if(*++cp == ':') {
if(argv[optind][sp+1] != '\0') {
optarg = &argv[optind++][sp+1];
}
else if(++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return('?');
}
else {
optarg = argv[optind++];
}
sp = 1;
}
else {
if(argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return(c);
}
#ifdef HAS_WIN_GUI
char **getargv(char *cl, int *argc)
{
static char *argv[MAX_ARGC];
int i;
for(i = 0; i < MAX_ARGC; i++) {
argv[i] = cl;
LOOP:
cl++;
if(cl[0] == ' ') {
while(cl[1] == ' ') cl++;
*cl = 0;
cl++;
}
else {
if(cl[0]) {
goto LOOP;
}
i++;
break;
}
}
*argc = i;
return argv;
}
#endif
#endif /* HAS_GETOPT_H */

93
getopt.h Executable file
View File

@ -0,0 +1,93 @@
/*
Newsgroups: mod.std.unix
Subject: public domain AT&T getopt source
Date: 3 Nov 85 19:34:15 GMT
Here's something you've all been waiting for: the AT&T public domain
source for getopt(3). It is the code which was given out at the 1985
UNIFORUM conference in Dallas. I obtained it by electronic mail
directly from AT&T. The people there assure me that it is indeed
in the public domain.
25/1/2005 Henry Thomas <me(at)henri.net>
Ported this original AT&T version of 'getopt' to windows.
Added documentation to this header, so know what everything does.
*/
#ifndef GETOPT_H_
#define GETOPT_H_
#ifdef HAS_GETOPT_H
# include <getopt.h>
#else
#ifdef __cplusplus
extern "C" {
#endif
extern int opterr;
/* If the value of the 'opterr' variable is nonzero, then getopt prints an
error message to the standard error stream if it encounters an unknown option
character or an option with a missing required argument. The windows version
reports the error using a message box. This is the default behavior. If you
set this variable to zero, getopt does not print any messages, but it still
returns the character ? to indicate an error. */
extern int optopt;
/* When getopt encounters an unknown option character or an option with a
missing required argument, it stores that option character the 'optopt'
variable. You can use this for providing your own diagnostic messages. */
extern int optind;
/* The 'optind' variable is set by getopt to the index of the next element of
the argv array to be processed. Once getopt has found all of the option
arguments, you can use this variable to determine where the remaining
non-option arguments begin. The initial value of this variable is 1. */
extern char *optarg;
/* The 'optarg' variable is set by getopt to point at the value of the
option argument, for those options that accept arguments. */
int getopt(int argc, char **argv, char *opts);
/* The getopt function gets the next option argument from the argument list
specified by the argv and argc arguments. Normally these values come directly
from the arguments received by main.
The options argument is a string that specifies the option characters that are
valid for this program. An option character in this string can be followed
by a colon (':') to indicate that it takes a required argument. */
#ifdef WIN32
#ifndef HAS_WIN_CLI
#define HAS_WIN_GUI 1
#endif
/* Define 'HAS_WIN_CLI' if you plan to use this version of getopt in a
windows console application */
#define MAX_ARGC 32
/* This is the maximum argument count that 'getargv' will return. */
char **getargv(char *cl, int *argc);
/* Parse a single command line sting and convert it into an argc/argv pair
compatible with getopt */
#endif
#ifdef __cplusplus
}
#endif
#endif /* HAS_GETOPT_H */
#endif /* GETOPT_H_ */

335
gpx.c
View File

@ -32,7 +32,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#ifdef _WIN32
#include "getopt.h"
#else
#include <unistd.h>
#endif
#include "gpx.h"
@ -47,6 +52,7 @@ static Machine replicator_1 = {
{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
1, // extruder count
20, // timeout
};
@ -57,6 +63,7 @@ static Machine replicator_1D = {
{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
2, // extruder count
20, // timeout
};
@ -67,6 +74,7 @@ static Machine replicator_2 = {
{1170, 1100, 400, ENDSTOP_IS_MIN}, // z axis
{1600, 96.275201870333662468889989185642, 3200, 0}, // a extruder
{1600, 96.275201870333662468889989185642, 3200, 0}, // b extruder
1.75, // nominal filament diameter
1, // extruder count
20, // timeout
};
@ -77,6 +85,7 @@ static Machine replicator_2X = {
{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
2, // extruder count
20, // timeout
};
@ -89,6 +98,7 @@ Machine machine = {
{1170, 400, ENDSTOP_IS_MIN}, // z axis
{1600, 96.275201870333662468889989185642, 3200, 0}, // a extruder
{1600, 96.275201870333662468889989185642, 3200, 0}, // b extruder
1.75, // nominal filament diameter
1, // extruder count
20, // timeout
};
@ -100,9 +110,8 @@ static double get_home_feedrate(int flag);
// GLOBAL VARIABLES
Command command; // the gcode command line
Point5d currentPosition; // the extruders current position in 5D space
Point5d machineTarget; // machine target point
Point5d workTarget; // work target point (including G10 offsets)
Point5d currentPosition; // the current position of the extruder in 5D space
Point5d targetPosition; // the target poaition the extruder will move to (including G10 offsets)
Point2d excess; // the accumulated rounding error in mm to step conversion
int currentExtruder; // the currently selectd extruder using Tn
double currentFeedrate; // the current feed rate
@ -114,6 +123,7 @@ int positionKnown; // is the current extruder position known
int programState; // gcode program state used to trigger start and end code sequences
unsigned line_number; // the current line number in the gcode file
static char buffer[256]; // the statically allocated parse-in-place buffer
double scale[2]; // A & B scaling for n x 0.01 mm change in nominal diameter
FILE *in; // the gcode input file stream
FILE *out; // the x3g output file stream
@ -195,6 +205,9 @@ static void initialize_globals(void)
programState = 0;
line_number = 1;
scale[0] = 0;
scale[1] = 0;
}
// STATE
@ -388,7 +401,9 @@ double get_safe_feedrate(int flag, Ptr5d delta) {
return feedrate;
}
// convert mm to steps using the current machine definition and accumulate the rounding error
// convert mm to steps using the current machine definition
// IMPORTANT: this command changes the global excess value which accunulates the rounding remainder
static Point5d mm_to_steps(Ptr5d mm, Ptr2d excess)
{
@ -398,12 +413,15 @@ static Point5d mm_to_steps(Ptr5d mm, Ptr2d excess)
result.y = round(mm->y * machine.y.steps_per_mm);
result.z = round(mm->z * machine.z.steps_per_mm);
if(excess) {
// accumulate rounding remainder
value = (mm->a * machine.a.steps_per_mm) + excess->a;
result.a = round(value);
// changes to excess
excess->a = value - result.a;
value = (mm->b * machine.b.steps_per_mm) + excess->b;
result.b = round(value);
// changes to excess
excess->b = value - result.b;
}
else {
@ -449,7 +467,6 @@ static void home_axes(unsigned direction)
if(direction != machine.y.endstop) {
fprintf(stderr, "(line %u) Semantic Warning: Y axis homing to %s endstop" EOL, line_number, direction ? "maximum" : "minimum");
}
}
if(xyz_flag & Z_IS_SET) {
if(machine.z.home_feedrate < feedrate) {
@ -522,6 +539,8 @@ static void wait_for_extruder(unsigned extruder_id, unsigned timeout)
// 136 - extruder action command
// Action 03 - Set toolhead target temperature
static void set_extruder_temperature(unsigned extruder_id, unsigned temperature)
{
assert(extruder_id < machine.extruder_count);
@ -540,6 +559,8 @@ static void set_extruder_temperature(unsigned extruder_id, unsigned temperature)
if(write_16(temperature) == EOF) exit(1);
}
// Action 12 - Enable / Disable fan
static void set_fan(unsigned extruder_id, unsigned state)
{
assert(extruder_id < machine.extruder_count);
@ -558,6 +579,8 @@ static void set_fan(unsigned extruder_id, unsigned state)
if(write_8(state) == EOF) exit(1);
}
// Action 13 - Enable / Disable extra output (blower fan)
static void set_valve(unsigned extruder_id, unsigned state)
{
assert(extruder_id < machine.extruder_count);
@ -576,6 +599,8 @@ static void set_valve(unsigned extruder_id, unsigned state)
if(write_8(state) == EOF) exit(1);
}
// Action 31 - Set build platform target temperature
static void set_build_platform_temperature(unsigned extruder_id, unsigned temperature)
{
assert(extruder_id < machine.extruder_count);
@ -594,7 +619,7 @@ static void set_build_platform_temperature(unsigned extruder_id, unsigned temper
if(write_16(temperature) == EOF) exit(1);
}
// 137 - Enable/disable axes steppers
// 137 - Enable / Disable axes steppers
static void set_steppers(unsigned axes, unsigned state)
{
@ -613,7 +638,7 @@ static void set_steppers(unsigned axes, unsigned state)
static void queue_absolute_point()
{
long longestDDA = get_longest_dda();
Point5d steps = mm_to_steps(&workTarget, &excess);
Point5d steps = mm_to_steps(&targetPosition, &excess);
if(write_8(139) == EOF) exit(1);
@ -634,16 +659,13 @@ static void queue_absolute_point()
// uint32: Feedrate, in microseconds between steps on the max delta. (DDA)
if(write_32((int)longestDDA) == EOF) exit(1);
currentPosition = machineTarget;
positionKnown = 1;
}
// 140 - Set extended position
static void set_position()
{
Point5d steps = mm_to_steps(&workTarget, &excess);
Point5d steps = mm_to_steps(&currentPosition, NULL);
if(write_8(140) == EOF) exit(1);
// int32: X position, in steps
@ -719,9 +741,43 @@ static void set_pot_value(unsigned axis, unsigned value)
}
// 146 - Set RGB LED value
static void set_LED(unsigned red, unsigned green, unsigned blue, unsigned blink)
{
if(write_8(146) == EOF) exit(1);
// uint8: red value (all pix are 0-255)
if(write_8(red) == EOF) exit(1);
// uint8: green
if(write_8(green) == EOF) exit(1);
// uint8: blue
if(write_8(blue) == EOF) exit(1);
// uint8: blink rate (0-255 valid)
if(write_8(blink) == EOF) exit(1);
// uint8: 0 (reserved for future use)
if(write_8(0) == EOF) exit(1);
}
// 147 - Set Beep
static void set_beep(unsigned frequency, unsigned milliseconds)
{
if(write_8(147) == EOF) exit(1);
// uint16: frequency
if(write_16(frequency) == EOF) exit(1);
// uint16: buzz length in ms
if(write_16(milliseconds) == EOF) exit(1);
// uint8: 0 (reserved for future use)
if(write_8(0) == EOF) exit(1);
}
// 148 - Pause for button
// 149 - Display message to LCD
@ -836,10 +892,13 @@ static void end_build()
// 155 - Queue extended point x3g
// IMPORTANT: this command updates the parser state
static void queue_point(double feedrate)
{
Point5d deltaMM;
Point5d deltaSteps;
Point5d target = targetPosition;
// 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
@ -850,7 +909,7 @@ static void queue_point(double feedrate)
// compute the relative distance traveled along each axis and convert to steps
if(command.flag & X_IS_SET) {
deltaMM.x = machineTarget.x - currentPosition.x;
deltaMM.x = targetPosition.x - currentPosition.x;
deltaSteps.x = round(fabs(deltaMM.x) * machine.x.steps_per_mm);
}
else {
@ -859,7 +918,7 @@ static void queue_point(double feedrate)
}
if(command.flag & Y_IS_SET) {
deltaMM.y = machineTarget.y - currentPosition.y;
deltaMM.y = targetPosition.y - currentPosition.y;
deltaSteps.y = round(fabs(deltaMM.y) * machine.y.steps_per_mm);
}
else {
@ -868,7 +927,7 @@ static void queue_point(double feedrate)
}
if(command.flag & Z_IS_SET) {
deltaMM.z = machineTarget.z - currentPosition.z;
deltaMM.z = targetPosition.z - currentPosition.z;
deltaSteps.z = round(fabs(deltaMM.z) * machine.z.steps_per_mm);
}
else {
@ -877,7 +936,7 @@ static void queue_point(double feedrate)
}
if(command.flag & A_IS_SET) {
deltaMM.a = workTarget.a - currentPosition.a;
deltaMM.a = targetPosition.a - currentPosition.a;
deltaSteps.a = round(fabs(deltaMM.a) * machine.a.steps_per_mm);
}
else {
@ -886,7 +945,7 @@ static void queue_point(double feedrate)
}
if(command.flag & B_IS_SET) {
deltaMM.b = workTarget.b - currentPosition.b;
deltaMM.b = targetPosition.b - currentPosition.b;
deltaSteps.b = round(fabs(deltaMM.b) * machine.b.steps_per_mm);
}
else {
@ -898,8 +957,8 @@ static void queue_point(double feedrate)
if(magnitude(command.flag, &deltaSteps) > 0) {
double distance = magnitude(command.flag & XYZ_BIT_MASK, &deltaMM);
workTarget.a = -deltaMM.a;
workTarget.b = -deltaMM.b;
target.a = -deltaMM.a;
target.b = -deltaMM.b;
deltaMM.x = fabs(deltaMM.x);
deltaMM.y = fabs(deltaMM.y);
@ -933,8 +992,8 @@ static void queue_point(double feedrate)
double mmPerRevolution = machine.a.motor_steps * (1 / machine.a.steps_per_mm);
// set distance
deltaMM.a = numRevolutions * mmPerRevolution;
deltaSteps.a = round(fabs(workTarget.a - currentPosition.a) * machine.a.steps_per_mm);
workTarget.a = -deltaMM.a;
deltaSteps.a = round(fabs(targetPosition.a - currentPosition.a) * machine.a.steps_per_mm);
target.a = -deltaMM.a;
}
}
if(deltaMM.b == 0.0) {
@ -945,12 +1004,12 @@ static void queue_point(double feedrate)
double mmPerRevolution = machine.b.motor_steps * (1 / machine.b.steps_per_mm);
// set distance
deltaMM.b = numRevolutions * mmPerRevolution;
deltaSteps.b = round(fabs(workTarget.b - currentPosition.b) * machine.b.steps_per_mm);
workTarget.b = -deltaMM.b;
deltaSteps.b = round(fabs(targetPosition.b - currentPosition.b) * machine.b.steps_per_mm);
target.b = -deltaMM.b;
}
}
Point5d steps = mm_to_steps(&workTarget, &excess);
Point5d steps = mm_to_steps(&target, &excess);
double usec = (60 * 1000 * 1000 * minutes);
@ -987,8 +1046,6 @@ static void queue_point(double feedrate)
// uint16: feedrate in mm/s, multiplied by 64 to assist fixed point calculation on the bot
if(write_16((unsigned)(feedrate * 64.0)) == EOF) exit(1);
currentPosition = machineTarget;
}
}
@ -1358,30 +1415,30 @@ int main(int argc, char * argv[])
}
}
// CALCULATE TARGET POINT
// CALCULATE TARGET POSITION
// x
if(command.flag & X_IS_SET) {
machineTarget.x = isRelative ? (currentPosition.x + command.x) : command.x;
targetPosition.x = isRelative ? (currentPosition.x + command.x) : command.x;
}
else {
machineTarget.x = currentPosition.x;
targetPosition.x = currentPosition.x;
}
// y
if(command.flag & Y_IS_SET) {
machineTarget.y = isRelative ? (currentPosition.y + command.y) : command.y;
targetPosition.y = isRelative ? (currentPosition.y + command.y) : command.y;
}
else {
machineTarget.y = currentPosition.y;
targetPosition.y = currentPosition.y;
}
// z
if(command.flag & Z_IS_SET) {
machineTarget.z = isRelative ? (currentPosition.z + command.z) : command.z;
targetPosition.z = isRelative ? (currentPosition.z + command.z) : command.z;
}
else {
machineTarget.z = currentPosition.z;
targetPosition.z = currentPosition.z;
}
// we treat e as short hand for a or b being set
@ -1389,29 +1446,29 @@ int main(int argc, char * argv[])
if(command.flag & E_IS_SET) {
if(currentExtruder == 0) {
// a = e
machineTarget.a = isRelative ? (currentPosition.a + command.e) : command.e;
targetPosition.a = isRelative ? (currentPosition.a + command.e) : command.e;
command.flag |= A_IS_SET;
command.a = command.e;
// b
if(command.flag & B_IS_SET) {
machineTarget.b = isRelative ? (currentPosition.b + command.b) : command.b;
targetPosition.b = isRelative ? (currentPosition.b + command.b) : command.b;
}
else {
machineTarget.b = currentPosition.b;
targetPosition.b = currentPosition.b;
}
}
else {
// a
if(command.flag & A_IS_SET) {
machineTarget.a = isRelative ? (currentPosition.a + command.a) : command.a;
targetPosition.a = isRelative ? (currentPosition.a + command.a) : command.a;
}
else {
machineTarget.a = currentPosition.a;
targetPosition.a = currentPosition.a;
}
// b = e
machineTarget.b = isRelative ? (currentPosition.b + command.e) : command.e;
targetPosition.b = isRelative ? (currentPosition.b + command.e) : command.e;
command.flag |= B_IS_SET;
command.b = command.e;
}
@ -1419,17 +1476,17 @@ int main(int argc, char * argv[])
else {
// a
if(command.flag & A_IS_SET) {
machineTarget.a = isRelative ? (currentPosition.a + command.a) : command.a;
targetPosition.a = isRelative ? (currentPosition.a + command.a) : command.a;
}
else {
machineTarget.a = currentPosition.a;
targetPosition.a = currentPosition.a;
}
// b
if(command.flag & B_IS_SET) {
machineTarget.b = isRelative ? (currentPosition.b + command.b) : command.b;
targetPosition.b = isRelative ? (currentPosition.b + command.b) : command.b;
}
else {
machineTarget.b = currentPosition.b;
targetPosition.b = currentPosition.b;
}
}
@ -1438,13 +1495,11 @@ int main(int argc, char * argv[])
currentFeedrate = command.f;
}
// CALCULATE WORK OFFSET
// CALCULATE OFFSET
workTarget.x = machineTarget.x + offset[currentOffset].x;
workTarget.y = machineTarget.y + offset[currentOffset].y;
workTarget.z = machineTarget.z + offset[currentOffset].z;
workTarget.a = machineTarget.a;
workTarget.b = machineTarget.b;
if(command.flag & X_IS_SET) targetPosition.x += offset[currentOffset].x;
if(command.flag & Y_IS_SET) targetPosition.y += offset[currentOffset].y;
if(command.flag & Z_IS_SET) targetPosition.z += offset[currentOffset].z;
// INTERPRET COMMAND
@ -1455,12 +1510,14 @@ int main(int argc, char * argv[])
case 0:
if(command.flag & F_IS_SET) {
queue_point(currentFeedrate);
currentPosition = targetPosition;
positionKnown = 1;
}
else {
Point3d delta;
if(command.flag & X_IS_SET) delta.x = fabs(workTarget.x - currentPosition.x);
if(command.flag & Y_IS_SET) delta.y = fabs(workTarget.y - currentPosition.y);
if(command.flag & Z_IS_SET) delta.z = fabs(workTarget.z - currentPosition.z);
if(command.flag & X_IS_SET) delta.x = fabs(targetPosition.x - currentPosition.x);
if(command.flag & Y_IS_SET) delta.y = fabs(targetPosition.y - currentPosition.y);
if(command.flag & Z_IS_SET) delta.z = fabs(targetPosition.z - currentPosition.z);
double length = magnitude(command.flag & XYZ_BIT_MASK, (Ptr5d)&delta);
double candidate, feedrate = DBL_MAX;
if(command.flag & X_IS_SET && delta.x != 0.0) {
@ -1482,12 +1539,16 @@ int main(int argc, char * argv[])
feedrate = machine.x.max_feedrate;
}
queue_point(feedrate);
currentPosition = targetPosition;
positionKnown = 1;
}
break;
// G1 - Coordinated Motion
case 1:
queue_point(currentFeedrate);
currentPosition = targetPosition;
positionKnown = 1;
break;
// G2 - Clockwise Arc
@ -1508,15 +1569,21 @@ int main(int argc, char * argv[])
case 10:
if(command.flag & P_IS_SET && command.p >= 1.0 && command.p <= 6.0) {
i = (int)command.p;
if(command.flag & X_IS_SET) offset[i].x = machineTarget.x;
if(command.flag & Y_IS_SET) offset[i].y = machineTarget.y;
if(command.flag & Z_IS_SET) offset[i].z = machineTarget.z;
if(command.flag & X_IS_SET) offset[i].x = command.x;
if(command.flag & Y_IS_SET) offset[i].y = command.y;
if(command.flag & Z_IS_SET) offset[i].z = command.z;
}
else {
fprintf(stderr, "(line %u) Syntax Error: G10 is missing coordiante system, use Pn where n is 1-6" EOL, line_number);
exit(1);
}
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:
@ -1570,14 +1637,18 @@ int main(int argc, char * argv[])
break;
// G92 - Define current position on axes
case 92:
case 92: {
if(command.flag & X_IS_SET) currentPosition.x = command.x;
if(command.flag & Y_IS_SET) currentPosition.y = command.y;
if(command.flag & Z_IS_SET) currentPosition.z = command.z;
if(command.flag & A_IS_SET) currentPosition.a = command.a;
if(command.flag & B_IS_SET) currentPosition.b = command.b;
// check if we know where we are
int mask = machine.extruder_count == 1 ? (XYZ_BIT_MASK | A_IS_SET) : AXES_BIT_MASK;
if((command.flag & mask) == mask) positionKnown = 1;
set_position();
if(command.flag & X_IS_SET) currentPosition.x = machineTarget.x;
if(command.flag & Y_IS_SET) currentPosition.y = machineTarget.y;
if(command.flag & Z_IS_SET) currentPosition.z = machineTarget.z;
if(command.flag & A_IS_SET) currentPosition.a = machineTarget.a;
if(command.flag & B_IS_SET) currentPosition.b = machineTarget.b;
break;
}
// G130 - Set given axes potentiometer Value
case 130:
@ -1630,6 +1701,10 @@ int main(int argc, char * argv[])
}
if(extruder_id < machine.extruder_count) {
if(currentExtruder != extruder_id) {
// check for active G10 offset
if(currentOffset == currentExtruder + 1) {
currentOffset = extruder_id + 1;
}
currentExtruder = extruder_id;
change_extruder(extruder_id);
}
@ -1670,18 +1745,18 @@ int main(int argc, char * argv[])
case 71:
if(command.flag & COMMENT_IS_SET) {
if(command.flag & P_IS_SET) {
display_message(command.comment, command.p, 0);
display_message(command.comment, command.p, 1);
}
else {
display_message(command.comment, 0, 0);
display_message(command.comment, 0, 1);
}
}
else {
if(command.flag & P_IS_SET) {
display_message("Press M to continue", command.p, 0);
display_message("Press M to continue", command.p, 1);
}
else {
display_message("Press M to continue", 0, 0);
display_message("Press M to continue", 0, 1);
}
}
break;
@ -1732,6 +1807,9 @@ int main(int argc, char * argv[])
unsigned extruder_id = (unsigned)command.t;
if(extruder_id < machine.extruder_count) {
set_steppers(extruder_id == 0 ? A_IS_SET : B_IS_SET, 1);
tool[extruder_id].motor_enabled = 1;
// update the direction
tool[extruder_id].rpm = command.m == 101 ? fabs(tool[extruder_id].rpm) : -fabs(tool[extruder_id].rpm);
}
else {
fprintf(stderr, "(line %u) Semantic Warning: M%u cannot select non-existant extruder T%u" EOL, line_number, command.m, extruder_id);
@ -1740,6 +1818,9 @@ int main(int argc, char * argv[])
}
else {
set_steppers(currentExtruder == 0 ? A_IS_SET : B_IS_SET, 1);
tool[currentExtruder].motor_enabled = 1;
// update the direction
tool[currentExtruder].rpm = command.m == 101 ? fabs(tool[currentExtruder].rpm) : -fabs(tool[currentExtruder].rpm);
}
break;
@ -1749,6 +1830,7 @@ int main(int argc, char * argv[])
unsigned extruder_id = (unsigned)command.t;
if(extruder_id < machine.extruder_count) {
set_steppers(extruder_id == 0 ? A_IS_SET : B_IS_SET, 0);
tool[extruder_id].motor_enabled = 0;
}
else {
fprintf(stderr, "(line %u) Semantic Warning: M103 cannot select non-existant extruder T%u" EOL, line_number, extruder_id);
@ -1757,6 +1839,7 @@ int main(int argc, char * argv[])
}
else {
set_steppers(currentExtruder == 0 ? A_IS_SET : B_IS_SET, 0);
tool[currentExtruder].motor_enabled = 0;
}
break;
@ -1818,6 +1901,28 @@ int main(int argc, char * argv[])
}
break;
// M108 - set extruder motor 5D 'simulated' RPM
case 108:
if(command.flag & R_IS_SET) {
if(command.flag & T_IS_SET) {
unsigned extruder_id = (unsigned)command.t;
if(extruder_id < machine.extruder_count) {
tool[extruder_id].rpm = command.r;
}
else {
fprintf(stderr, "(line %u) Semantic Warning: M108 cannot select non-existant extruder T%u" EOL, line_number, extruder_id);
}
}
else {
tool[currentExtruder].rpm = command.r;
}
}
else {
fprintf(stderr, "(line %u) Syntax Error: M108 is missing motor RPM, use Rn where n is 0-5" EOL, line_number);
exit(1);
}
break;
// M109 - Set Build Platform Temperature
// M140 - Set Build Platform Temperature (skeinforge)
case 109:
@ -1879,22 +1984,6 @@ int main(int argc, char * argv[])
set_valve(currentExtruder, 0);
}
break;
// M137 - Enable axes steppers
case 137:
break;
// M138 - Disable axes steppers
case 138:
break;
// M146 - Set RGB LED value
case 146:
break;
// M147 - Set Beep
case 147:
break;
// M131 - Store Current Position to EEPROM
case 131:
@ -1921,6 +2010,56 @@ int main(int argc, char * argv[])
}
break;
// M137 - Enable axes steppers
case 137:
if(command.flag & AXES_BIT_MASK) {
set_steppers(command.flag & AXES_BIT_MASK, 1);
if(command.flag & A_IS_SET) tool[0].motor_enabled = 1;
if(command.flag & B_IS_SET) tool[1].motor_enabled = 1;
}
else {
fprintf(stderr, "(line %u) Syntax Error: M137 is missing axes, use X Y Z A B" EOL, line_number);
exit(1);
}
break;
// M138 - Disable axes steppers
case 138:
if(command.flag & AXES_BIT_MASK) {
set_steppers(command.flag & AXES_BIT_MASK, 0);
if(command.flag & A_IS_SET) tool[0].motor_enabled = 0;
if(command.flag & B_IS_SET) tool[1].motor_enabled = 0;
}
else {
fprintf(stderr, "(line %u) Syntax Error: M138 is missing axes, use X Y Z A B" EOL, line_number);
exit(1);
}
break;
// M146 - Set RGB LED value (RLS - P)
case 146: {
unsigned red = 0;
if(command.flag & R_IS_SET) red = (unsigned)command.r & 0xFF;
unsigned green = 0;
if(command.flag & L_IS_SET) green = (unsigned)command.l & 0xFF;
unsigned blue = 0;
if(command.flag & S_IS_SET) blue = (unsigned)command.s & 0xFF;
unsigned blink = 0;
if(command.flag & P_IS_SET) blink = (unsigned)command.p & 0xFF;
set_LED(red, green, blue, blink);
break;
}
// M147 - Set Beep (SP)
case 147: {
unsigned frequency = 6000;
if(command.flag & S_IS_SET) frequency = (unsigned)command.s & 0xFFFF;
unsigned milliseconds = 100;
if(command.flag & P_IS_SET) milliseconds = (unsigned)command.p & 0xFFFF;
set_beep(frequency, milliseconds);
break;
}
// M320 - Acceleration on for subsequent instructions
case 320:
set_acceleration(1);
@ -1934,23 +2073,31 @@ int main(int argc, char * argv[])
fprintf(stderr, "(line %u) Syntax Warning: unsupported mcode command 'M%u'" EOL, line_number, command.m);
}
}
else if(command.flag & T_IS_SET) {
unsigned extruder_id = (unsigned)command.t;
if(extruder_id < machine.extruder_count) {
if(currentExtruder != extruder_id) {
currentExtruder = extruder_id;
change_extruder(extruder_id);
command_line++;
else {
if(command.flag & T_IS_SET) {
unsigned extruder_id = (unsigned)command.t;
if(extruder_id < machine.extruder_count) {
if(currentExtruder != extruder_id) {
command_line++;
// check for active G10 offset
if(currentOffset == currentExtruder + 1) {
currentOffset = extruder_id + 1;
}
currentExtruder = extruder_id;
change_extruder(extruder_id);
}
}
else {
fprintf(stderr, "(line %u) Semantic Warning: T%u cannot select non-existant extruder" EOL, line_number, extruder_id);
}
}
else {
fprintf(stderr, "(line %u) Semantic Warning: T%u cannot select non-existant extruder" EOL, line_number, extruder_id);
if(command.flag & AXES_BIT_MASK) {
command_line++;
queue_point(currentFeedrate);
currentPosition = targetPosition;
positionKnown = 1;
}
}
else if(command.flag & AXES_BIT_MASK) {
command_line++;
queue_point(currentFeedrate);
}
// update progress
if(filesize && build_percent && command_line) {
unsigned percent = (unsigned)round(100.0 * (double)ftell(in) / (double)filesize);

1
gpx.h
View File

@ -142,6 +142,7 @@ typedef struct tMachine {
Axis z;
Extruder a;
Extruder b;
double filament_diameter;
unsigned extruder_count;
unsigned timeout;
} Machine;

View File

@ -19,6 +19,7 @@
; 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
; PREFIX
M70 (M103 - extruder off)
@ -58,16 +59,11 @@ G10 P4 X40 Y40 Z40
G10 P5 X50 Y50 Z50
G10 P6 X60 Y60 Z60
; G20 - Use Inches as Units
; G70 - Use Inches as Units
;M70 (G20 - imperial units)
;G20
;G1 X1 Y1 Z1 E0.197
; G21 - Use Milimeters as Units
; G71 - Use Milimeters as Units
;M70 (G21 - metric units)
;G21
M70 (G21 - metric units)
G21
G71
; G28 - Home given axes to maximum
M70 (G28 - home to max)
@ -147,18 +143,6 @@ M70 (M104 - set temp)
M104 S230 T0
M104 S230 T1
; M3 - Spindle On - Clockwise
;M70 (M3 - spindle on)
;M3
; M4 - Spindle On - Counter Clockwise
;M70 (M4 - spindle on)
;M4
; M5 - Spindle Off
;M70 (M5 - spindle off)
;M5
; M6 - Wait for toolhead to come up to reach (or exceed) temperature
M70 (M6 - wait for tool)
M6 T0
@ -188,32 +172,6 @@ M6
M70 (T1 - tool change)
T1
; M13 - Spindle CW and Coolant A On
;M70 (M13 - spindle +cool)
;M13
; M14 - Spindle CCW and Coolant A On
;M70 (M14 - spindle +cool)
;M14
; M17 - Enable Motor(s)
;M70 (M17 - enable motor)
;M17
; M18 - Disable Motor(s)
;M70 (M18 - disable motor)
;M18
; M21 - Open Collet
;M70 (M21 - open collet)
;M21
; M22 - Close Collet
;M70 (M22 - close collet)
;M22
; M30 - Program Rewind
; M70 - Display Message On Machine
M70 P20 (This is a really large message that will take up quite a few rows to display on the makerbot LCD screen)
@ -232,34 +190,85 @@ M70 (M73 - progress)
M73 P10 (build progress)
; M101 - Turn Extruder On, Forward
M70 (M101 - extruder on-f)
M101 T1
M101 T0
; M102 - Turn Extruder On, Reverse
M70 (M102 - extruder on-r)
M102 T1
M102 T0
; M103 - Turn Extruder Off
M70 (M103 - extruder off)
M103 T1
M103 T0
; M104 - Set Temperature
; M105 - Get Temperature
; M106 - Turn Automated Build Platform (or the Fan, on older models) On
; M107 - Turn Automated Build Platform (or the Fan, on older models) Off
; M108 - Set Extruder's Max Speed (R = RPM, P = PWM)
M70 (M104 - set temp)
M104 T1 S240
M104 T0 S230
; M108 - Set Extruder's Max Speed (R = RPM)
M70 (M108 - set rpm)
M108 T1 R5.0
M108 T0 R3.0
; M109 - Set Build Platform Temperature
; M110 - Set Build Chamber Temperature
M70 (M109 - hbp temp)
M109 S110
; M126 - Valve Open
M70 (M126 - blower on)
M126
; M127 - Valve Close
; M128 - "Get Position
M70 (M127 - blower off)
M127
; M131 - Store Current Position to EEPROM
M70 (M131 - store EEPROM)
M131 X Y Z A B
; M132 - Load Current Position from EEPROM
M70 (M132 - load EEPROM)
M132 X Y Z A B
; M137 - Enable axes steppers
M70 (M137 - steppers on)
M132 X Y Z A B
; M138 - Disable axes steppers
M70 (M138 - steppers on)
M138 X Y Z A B
; M146 - Set RGB LED value
M70 (M146 - set LED)
M146 R255 L0 S0 P0
; M147 - Set Beep
M70 (M147 - set beep)
M147 S4000 P100
; M140 - Set Build Platform Temperature
; M141 - Set Chamber Temperature (Ignored)
; M142 - Set Chamber Holding Pressure (Ignored)
; M200 - Reset driver
; M300 - Set Servo 1 Position
; M301 - Set Servo 2 Position
; M310 - Start data capture
; M311 - Stop data capture
; M312 - Log a note to the data capture store
M70 (M140 - hbp temp)
M140 T0 S100
; M320 - Acceleration on for subsequent instructions
M70 (M320 - acc on)
M320
; M321 - Acceleration off for subsequent instructions
M70 (M21 - acc off)
M321
; T1 - Set Current Tool 1
M70 (T1 - set tool)
T1
; T0 - Set Current Tool 0
; T1 - Set Current Tool 1
M70 (T0 - set tool)
T0
;POSTFIX
M70 (M73 - end build)

179
s3g-decompiler.py Normal file
View File

@ -0,0 +1,179 @@
#!/usr/bin/python
#
# s3g-decompiler.py
#
# Created by Adam Mayer on Jan 25 2011.
#
# Originally from ReplicatorG sources /src/replicatorg/scripts
# which are part of the ReplicatorG project - http://www.replicat.org
#
# 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
import struct
import sys
toolCommandTable = {
1: ("", "[1] init: Initialize firmware to boot state"),
3: ("<H", "[3] Extruder: set temperature = %i"),
4: ("<B", "[4] Motor 1: set speed (PWM) = %i"),
5: ("<B", "[5] Motor 2: set speed (PWM) = %i"),
6: ("<I", "[6] Motor 1: set speed (RPM) = %i"),
7: ("<I", "[7] Motor 2: set speed (RPM) = %i"),
8: ("<I", "[8] Motor 1: set direction = %i"),
9: ("<I", "[9] Motor 2: set direction = %i"),
10: ("B", "[10] Motor 1: toggle = %d"),
11: ("B", "[11] Motor 2: toggle = %d"),
12: ("B", "[12] Fan: toggle = %d"),
13: ("B", "[13] Valve: toggle = %d"),
13: ("B", "[14] Servo 1: angle = %d"),
13: ("B", "[15] Serve 2: angle = %d"),
27: ("B", "[27] Automated build platform: toggle = %d"),
31: ("<H", "[31] Build Platform: set temperature = %i"),
}
def parseToolAction():
global s3gFile
packetStr = s3gFile.read(3)
if len(packetStr) != 3:
raise "Incomplete s3g file during tool command parse"
(index,command,payload) = struct.unpack("<BBB",packetStr)
contents = s3gFile.read(payload)
if len(contents) != payload:
raise "Incomplete s3g file: tool packet truncated"
return (index,command,contents)
def printToolAction(tuple):
print "\t[136] Tool %i:" % (tuple[0]),
# command - tuple[1]
# data - tuple[2]
(parse, disp) = toolCommandTable[tuple[1]]
if type(parse) == type(""):
packetLen = struct.calcsize(parse)
if len(tuple[2]) != packetLen:
raise "Packet incomplete"
parsed = struct.unpack(parse,tuple[2])
else:
parsed = parse()
if type(disp) == type(""):
print disp % parsed
def parseDisplayMessageAction():
global s3gFile
packetStr = s3gFile.read(4)
if len(packetStr) < 4:
raise "Incomplete s3g file during tool command parse"
(options,offsetX,offsetY,timeout) = struct.unpack("<BBBB",packetStr)
message = "";
while True:
c = s3gFile.read(1);
if c == '\0':
break;
else:
message += c;
return (options,offsetX,offsetY,timeout,message)
def parseBuildStartNotificationAction():
global s3gFile
packetStr = s3gFile.read(4)
if len(packetStr) < 4:
raise "Incomplete s3g file during tool command parse"
(steps) = struct.unpack("<i",packetStr)
buildName = "";
while True:
c = s3gFile.read(1);
if c == '\0':
break;
else:
buildName += c;
return (steps[0],buildName)
# Command table entries consist of:
# * The key: the integer command code
# * A tuple:
# * idx 0: the python struct description of the rest of the data,
# of a function that unpacks the remaining data from the
# stream
# * idx 1: either a format string that will take the tuple of unpacked
# data, or a function that takes the tuple as input and returns
# a string
# REMINDER: all values are little-endian. Struct strings with multibyte
# types should begin with "<".
# For a refresher on Python struct syntax, see here:
# http://docs.python.org/library/struct.html
commandTable = {
129: ("<iiiI","\t[129] Absolute move to (%i,%i,%i) at DDA %i"),
130: ("<iii","\t[130] Machine position set as (%i,%i,%i)"),
131: ("<BIH","\t[131] Home minimum on %X, feedrate %i, timeout %i s"),
132: ("<BIH","\t[132] Home maximum on %X, feedrate %i, timeout %i s"),
133: ("<I","\t[133] Delay of %i us"),
134: ("<B","\t[134] Switch to tool %i"),
135: ("<BHH","\t[135] Wait for tool %i (%i ms between polls, %i s timeout"),
136: (parseToolAction, printToolAction),
137: ("<B", "\t[137] Enable/disable axes %X"),
138: ("<H", "\t[138] User block on ID %i"),
139: ("<iiiiiI","\t[139] Absolute move to (%i,%i,%i,%i,%i) at DDA %i"),
140: ("<iiiii","\t[140] Extended Machine position set as (%i,%i,%i,%i,%i)"),
141: ("<BHH","\t[141] Wait for platform %i (%i ms between polls, %i s timeout)"),
142: ("<iiiiiIB","\t[142] Move to (%i,%i,%i,%i,%i) in %i us (relative: %X)"),
143: ("<b","\t[143] Store home position for axes %d"),
144: ("<b","\t[144] Recall home position for axes %d"),
145: ("<BB","\t[145] Set pot axis %i to %i"),
146: ("<BBBBB","\t[146] Set RGB led red %i, green %i, blue %i, blink rate %i, effect %i"),
147: ("<HHB","\t[147] Set beep, frequency %i, length %i, effect %i"),
148: ("<BHB","\t[148] Pause for button 0x%X, timeout %i s, timeout_bevavior %i"),
149: (parseDisplayMessageAction, "\t[149] Display message, options 0x%X at %i,%i timeout %i\n %s"),
150: ("<BB","\t[150] Set build percent %i%%, ignore %i"),
151: ("<B","\t[151] Queue song %i"),
152: ("<B","\t[152] Reset to factory, options 0x%X"),
153: (parseBuildStartNotificationAction, "\t[153] Start build, steps %i: %s"),
154: ("<B","\t[154] End build, flags 0x%X"),
155: ("<iiiiiIBfh","\t[155] Move to (%i,%i,%i,%i,%i) dda_rate: %i (relative: %X) distance: %f feedrateX64: %i"),
156: ("<B","\t[156] Set acceleration to %i"),
157: ("<BBBIHHIIB","\t[157] Stream version %i.%i (%i %i %i %i %i %i %i)"),
}
def parseNextCommand():
"""Parse and handle the next command. Returns
True for success, False on EOF, and raises an
exception on corrupt data."""
global s3gFile
commandStr = s3gFile.read(1)
if len(commandStr) == 0:
print "EOF"
return False
sys.stdout.write(str(lineNumber) + ': ')
(command) = struct.unpack("B",commandStr)
(parse, disp) = commandTable[command[0]]
if type(parse) == type(""):
packetLen = struct.calcsize(parse)
packetData = s3gFile.read(packetLen)
if len(packetData) != packetLen:
raise "Packet incomplete"
parsed = struct.unpack(parse,packetData)
else:
parsed = parse()
if type(disp) == type(""):
print disp % parsed
else:
disp(parsed)
return True
s3gFile = open(sys.argv[1],'rb')
lineNumber = 0
while parseNextCommand():
lineNumber = lineNumber + 1