/// wait for queue to empty void queue_wait() { for (;queue_empty() == 0;) { ifclock(clock_flag_10ms) { clock_10ms(); } } }
/// this is where it all starts, and ends /// /// just run init(), then run an endless loop where we pass characters from the serial RX buffer to gcode_parse_char() and check the clocks int main (void) { init(); // main loop for (;;) { // if queue is full, no point in reading chars- host will just have to wait if ((serial_rxchars() != 0) && (queue_full() == 0)) { uint8_t c = serial_popchar(); gcode_parse_char(c); } ifclock(clock_flag_10ms) { clock_10ms(); } } }
void process_gcode_command() { uint32_t backup_f; // convert relative to absolute if (next_target.option_relative) { next_target.target.X += startpoint.X; next_target.target.Y += startpoint.Y; next_target.target.Z += startpoint.Z; } // E ALWAYS relative, otherwise we overflow our registers after only a few layers // next_target.target.E += startpoint.E; // easier way to do this // startpoint.E = 0; // moved to dda.c, end of dda_create() and dda_queue.c, next_move() // implement axis limits #ifdef X_MIN if (next_target.target.X < (X_MIN * STEPS_PER_MM_X)) next_target.target.X = X_MIN * STEPS_PER_MM_X; #endif #ifdef X_MAX if (next_target.target.X > (X_MAX * STEPS_PER_MM_X)) next_target.target.X = X_MAX * STEPS_PER_MM_X; #endif #ifdef Y_MIN if (next_target.target.Y < (Y_MIN * STEPS_PER_MM_Y)) next_target.target.Y = Y_MIN * STEPS_PER_MM_Y; #endif #ifdef Y_MAX if (next_target.target.Y > (Y_MAX * STEPS_PER_MM_Y)) next_target.target.Y = Y_MAX * STEPS_PER_MM_Y; #endif #ifdef Z_MIN if (next_target.target.Z < (Z_MIN * STEPS_PER_MM_Z)) next_target.target.Z = Z_MIN * STEPS_PER_MM_Z; #endif #ifdef Z_MAX if (next_target.target.Z > (Z_MAX * STEPS_PER_MM_Z)) next_target.target.Z = Z_MAX * STEPS_PER_MM_Z; #endif if (next_target.seen_T) { next_tool = next_target.T; } if (next_target.seen_G) { uint8_t axisSelected = 0; switch (next_target.G) { // G0 - rapid, unsynchronised motion // since it would be a major hassle to force the dda to not synchronise, just provide a fast feedrate and hope it's close enough to what host expects case 0: backup_f = next_target.target.F; next_target.target.F = MAXIMUM_FEEDRATE_X * 2L; enqueue(&next_target.target); next_target.target.F = backup_f; break; // G1 - synchronised motion case 1: enqueue(&next_target.target); break; // G2 - Arc Clockwise // unimplemented // G3 - Arc Counter-clockwise // unimplemented // G4 - Dwell case 4: // wait for all moves to complete queue_wait(); // delay for (;next_target.P > 0;next_target.P--) { ifclock(CLOCK_FLAG_10MS) { clock_10ms(); } delay_ms(1); } break; // G20 - inches as units case 20: next_target.option_inches = 1; break; // G21 - mm as units case 21: next_target.option_inches = 0; break; // G30 - go home via point case 30: enqueue(&next_target.target); // no break here, G30 is move and then go home // G28 - go home case 28: queue_wait(); if (next_target.seen_X) { zero_x(); axisSelected = 1; } if (next_target.seen_Y) { zero_y(); axisSelected = 1; } if (next_target.seen_Z) { zero_z(); axisSelected = 1; } if (next_target.seen_E) { zero_e(); axisSelected = 1; } if (!axisSelected) { zero_x(); zero_y(); zero_z(); zero_e(); } break; // G90 - absolute positioning case 90: next_target.option_relative = 0; break; // G91 - relative positioning case 91: next_target.option_relative = 1; break; // G92 - set home case 92: // wait for queue to empty queue_wait(); if (next_target.seen_X) { startpoint.X = current_position.X = next_target.target.X; axisSelected = 1; } if (next_target.seen_Y) { startpoint.Y = current_position.Y = next_target.target.Y; axisSelected = 1; } if (next_target.seen_Z) { startpoint.Z = current_position.Z = next_target.target.Z; axisSelected = 1; } if (next_target.seen_E) { startpoint.E = current_position.E = next_target.target.E; axisSelected = 1; } if (axisSelected == 0) { startpoint.X = current_position.X = startpoint.Y = current_position.Y = startpoint.Z = current_position.Z = startpoint.E = current_position.E = 0; } break; // G161 - Home negative case 161: if (next_target.seen_X) home_x_negative(); if (next_target.seen_Y) home_y_negative(); if (next_target.seen_Z) home_z_negative(); break; // G162 - Home positive case 162: if (next_target.seen_X) home_x_positive(); if (next_target.seen_Y) home_y_positive(); if (next_target.seen_Z) home_z_positive(); break; // unknown gcode: spit an error default: sersendf_P(PSTR("E: Bad G-code %d"), next_target.G); // newline is sent from gcode_parse after we return return; } #ifdef DEBUG print_queue(); #endif }
void process_gcode_command() { uint32_t backup_f; // convert relative to absolute if (next_target.option_relative) { next_target.target.X += startpoint.X; next_target.target.Y += startpoint.Y; next_target.target.Z += startpoint.Z; #ifdef E_ABSOLUTE next_target.target.E += startpoint.E; #endif } // E ALWAYS relative, otherwise we overflow our registers after only a few layers // next_target.target.E += startpoint.E; // easier way to do this // startpoint.E = 0; // moved to dda.c, end of dda_create() and dda_queue.c, next_move() // implement axis limits #ifdef X_MIN if (next_target.target.X < (X_MIN * STEPS_PER_MM_X)) next_target.target.X = X_MIN * STEPS_PER_MM_X; #endif #ifdef X_MAX if (next_target.target.X > (X_MAX * STEPS_PER_MM_X)) next_target.target.X = X_MAX * STEPS_PER_MM_X; #endif #ifdef Y_MIN if (next_target.target.Y < (Y_MIN * STEPS_PER_MM_Y)) next_target.target.Y = Y_MIN * STEPS_PER_MM_Y; #endif #ifdef Y_MAX if (next_target.target.Y > (Y_MAX * STEPS_PER_MM_Y)) next_target.target.Y = Y_MAX * STEPS_PER_MM_Y; #endif #ifdef Z_MIN if (next_target.target.Z < (Z_MIN * STEPS_PER_MM_Z)) next_target.target.Z = Z_MIN * STEPS_PER_MM_Z; #endif #ifdef Z_MAX if (next_target.target.Z > (Z_MAX * STEPS_PER_MM_Z)) next_target.target.Z = Z_MAX * STEPS_PER_MM_Z; #endif // The GCode documentation was taken from http://reprap.org/wiki/Gcode . if (next_target.seen_T) { //? ==== T: Select Tool ==== //? //? Example: T1 //? //? Select extruder number 1 to build with. Extruder numbering starts at 0. next_tool = next_target.T; } if (next_target.seen_G) { uint8_t axisSelected = 0; switch (next_target.G) { // G0 - rapid, unsynchronised motion // since it would be a major hassle to force the dda to not synchronise, just provide a fast feedrate and hope it's close enough to what host expects case 0: //? ==== G0: Rapid move ==== //? //? Example: G0 X12 //? //? In this case move rapidly to X = 12 mm. In fact, the RepRap firmware uses exactly the same code for rapid as it uses for controlled moves (see G1 below), as - for the RepRap machine - this is just as efficient as not doing so. (The distinction comes from some old machine tools that used to move faster if the axes were not driven in a straight line. For them G0 allowed any movement in space to get to the destination as fast as possible.) backup_f = next_target.target.F; next_target.target.F = MAXIMUM_FEEDRATE_X * 2L; enqueue(&next_target.target); next_target.target.F = backup_f; break; // G1 - synchronised motion case 1: //? ==== G1: Controlled move ==== //? //? Example: G1 X90.6 Y13.8 E22.4 //? //? Go in a straight line from the current (X, Y) point to the point (90.6, 13.8), extruding material as the move happens from the current extruded length to a length of 22.4 mm. enqueue(&next_target.target); break; // G2 - Arc Clockwise // unimplemented // G3 - Arc Counter-clockwise // unimplemented // G4 - Dwell case 4: //? ==== G4: Dwell ==== //? //? Example: G4 P200 //? //? In this case sit still doing nothing for 200 milliseconds. During delays the state of the machine (for example the temperatures of its extruders) will still be preserved and controlled. //? // wait for all moves to complete queue_wait(); // delay for (;next_target.P > 0;next_target.P--) { ifclock(clock_flag_10ms) { clock_10ms(); } delay_ms(1); } break; // G20 - inches as units case 20: //? ==== G20: Set Units to Inches ==== //? //? Example: G20 //? //? Units from now on are in inches. //? next_target.option_inches = 1; break; // G21 - mm as units case 21: //? ==== G21: Set Units to Millimeters ==== //? //? Example: G21 //? //? Units from now on are in millimeters. (This is the RepRap default.) //? next_target.option_inches = 0; break; // G30 - go home via point case 30: //? ==== G30: Go home via point ==== //? //? Undocumented. enqueue(&next_target.target); // no break here, G30 is move and then go home // G28 - go home case 28: //? ==== G28: Move to Origin ==== //? //? Example: G28 //? //? This causes the RepRap machine to move back to its X, Y and Z zero endstops. It does so //? accelerating, so as to get there fast. But when it arrives it backs off by 1 mm in each //? direction slowly, then moves back slowly to the stop. This ensures more accurate positioning. //? //? If you add coordinates, then just the axes with coordinates specified will be zeroed. Thus //? //? G28 X0 Y72.3 //? //? will zero the X and Y axes, but not Z. The actual coordinate values are ignored. //? queue_wait(); if (next_target.seen_X) { zero_x(); axisSelected = 1; } if (next_target.seen_Y) { zero_y(); axisSelected = 1; } if (next_target.seen_Z) { zero_z(); axisSelected = 1; } // there's no point in moving E, as E has no endstops if (!axisSelected) { zero_x(); zero_y(); zero_z(); } break; // G90 - absolute positioning case 90: //? ==== G90: Set to Absolute Positioning ==== //? //? Example: G90 //? //? All coordinates from now on are absolute relative to the origin of the machine. (This is the RepRap default.) next_target.option_relative = 0; break; // G91 - relative positioning case 91: //? ==== G91: Set to Relative Positioning ==== //? //? Example: G91 //? //? All coordinates from now on are relative to the last position. next_target.option_relative = 1; break; // G92 - set home case 92: //? ==== G92: Set Position ==== //? //? Example: G92 X10 E90 //? //? Allows programming of absolute zero point, by reseting the current position to the values specified. This would set the machine's X coordinate to 10, and the extrude coordinate to 90. No physical motion will occur. // wait for queue to empty queue_wait(); if (next_target.seen_X) { startpoint.X = current_position.X = next_target.target.X; axisSelected = 1; } if (next_target.seen_Y) { startpoint.Y = current_position.Y = next_target.target.Y; axisSelected = 1; } if (next_target.seen_Z) { startpoint.Z = current_position.Z = next_target.target.Z; axisSelected = 1; } if (next_target.seen_E) { #ifdef E_ABSOLUTE startpoint.E = current_position.E = next_target.target.E; #endif axisSelected = 1; } if (axisSelected == 0) { startpoint.X = current_position.X = next_target.target.X = startpoint.Y = current_position.Y = next_target.target.Y = startpoint.Z = current_position.Z = next_target.target.Z = 0; } break; // G161 - Home negative case 161: //? ==== G161: Home negative ==== //? //? Find the minimum limit of the specified axes by searching for the limit switch. if (next_target.seen_X) home_x_negative(); if (next_target.seen_Y) home_y_negative(); if (next_target.seen_Z) home_z_negative(); break; // G162 - Home positive case 162: //? ==== G162: Home positive ==== //? //? Find the maximum limit of the specified axes by searching for the limit switch. if (next_target.seen_X) home_x_positive(); if (next_target.seen_Y) home_y_positive(); if (next_target.seen_Z) home_z_positive(); break; // unknown gcode: spit an error default: sersendf_P(PSTR("E: Bad G-code %d"), next_target.G); // newline is sent from gcode_parse after we return return; } #ifdef DEBUG if (DEBUG_POSITION && (debug_flags & DEBUG_POSITION)) print_queue(); #endif }