Skip to content

Commit

Permalink
Merge pull request #511 from bdring/Devt
Browse files Browse the repository at this point in the history
Devt
  • Loading branch information
bdring authored Jun 24, 2022
2 parents d7189a0 + c1221a8 commit f02a972
Show file tree
Hide file tree
Showing 14 changed files with 895 additions and 703 deletions.
15 changes: 6 additions & 9 deletions FluidNC/ld/esp32/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,17 @@ capabilities to let us use a modified script.
### How It Normally Works

PlatformIO specifies the list of linker scripts via the Python script
~/.platformio/packages/framework-arduinoespressif32/tools/platformio-build.py .
The files are esp32.project.ld, esp32.rom.ld, esp32.peripherals.ld,
esp32.rom.libgcc.ld, and esp32.rom.spiram_incompatible_fns.ld .
The file that we need to change is esp32.project.ld ; the others can
be used as-is.
~/.platformio/packages/framework-arduinoespressif32/tools/platformio-build-esp32.py .
The file we care about is sections.ld ; the others can be used as-is.

The stock linker scripts are found in the directory
.platformio/packages/framework-arduinoespressif32/tools/sdk/ld . That
.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/ld . That
directory is specified in platformio-build.py via the environment
variable LIBPATH .

### Changes to esp32.project.ld
### Changes to sections.ld

First, we need to modify esp32.project.ld . We copy that file into
First, we need to modify sections.ld . We copy that file into
the FluidNC tree at ./FluidNC/ld/esp32/ (this directory). We then
add into that file the line

Expand All @@ -62,7 +59,7 @@ maintenance.

### Making PlatformIO Use the Modified File

To make PlatformIO use the modified esp32.project.ld instead
To make PlatformIO use the modified sections.ld instead
of the stock one, we use PlatformIO's "advanced scripting"
feature. In the platformio.ini [env] section, we add this line

Expand Down
620 changes: 0 additions & 620 deletions FluidNC/ld/esp32/esp32.project.ld

This file was deleted.

807 changes: 807 additions & 0 deletions FluidNC/ld/esp32/sections.ld

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions FluidNC/ld/esp32/vtable_in_dram.ld
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
*NullMotor.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*RcServo.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*Servo.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*Solenoid.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*StandardStepper.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*StepStick.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*TMC*Driver.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*TrinamicBase.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*TrinamicSpiDriver.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
*TrinamicUartDriver.cpp.o(.rodata .rodata.* .xt.prop .xt.prop.*)
Expand Down
2 changes: 1 addition & 1 deletion FluidNC/src/Configuration/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ namespace Configuration {
}
float fvalue;
if (str.isFloat(fvalue)) {
return int(round(fvalue));
return lroundf(fvalue);
}
parseError("Expected an integer value");
return 0;
Expand Down
101 changes: 55 additions & 46 deletions FluidNC/src/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,26 @@ Error gc_execute_line(char* line, Channel& channel) {
size_t axis_words = 0; // XYZ tracking
size_t ijk_words = 0; // IJK tracking
// Initialize command and value words and parser flags variables.
uint32_t command_words = 0; // Tracks G and M command words. Also used for modal group violations.
uint32_t value_words = 0; // Tracks value words.
uint8_t gc_parser_flags = GCParserNone;
auto n_axis = config->_axes->_numberAxis;
float coord_data[MAX_N_AXIS]; // Used by WCO-related commands
uint8_t pValue; // Integer value of P word
uint32_t command_words = 0; // Tracks G and M command words. Also used for modal group violations.
uint32_t value_words = 0; // Tracks value words.

bool jogMotion = false;
bool checkMantissa = false;
bool clockwiseArc = false;
bool probeAway = false;
bool probeNoError = false;
bool syncLaser = false;
bool disableLaser = false;
bool laserIsMotion = false;

auto n_axis = config->_axes->_numberAxis;
float coord_data[MAX_N_AXIS]; // Used by WCO-related commands
uint8_t pValue; // Integer value of P word

// Determine if the line is a jogging motion or a normal g-code block.
if (line[0] == '$') { // NOTE: `$J=` already parsed when passed to this function.
// Set G1 and G94 enforced modes to ensure accurate error checks.
gc_parser_flags |= GCParserJogMotion;
jogMotion = true;
gc_block.modal.motion = Motion::Linear;
gc_block.modal.feed_rate = FeedRate::UnitsPerMin;
if (config->_useLineNumbers) {
Expand All @@ -191,12 +200,8 @@ Error gc_execute_line(char* line, Channel& channel) {
float value;
uint8_t int_value = 0;
uint16_t mantissa = 0;
if (gc_parser_flags & GCParserJogMotion) {
char_counter = 3; // Start parsing after `$J=`
} else {
char_counter = 0;
}
while (line[char_counter] != 0) { // Loop until no more g-code words in line.
char_counter = jogMotion ? 3 : 0; // Start parsing after `$J=` if jogging
while (line[char_counter] != 0) { // Loop until no more g-code words in line.
// Import the next g-code word, expecting a letter followed by a value. Otherwise, error out.
letter = line[char_counter];
if ((letter < 'A') || (letter > 'Z')) {
Expand All @@ -213,8 +218,8 @@ Error gc_execute_line(char* line, Channel& channel) {
// a good enough compromise and catch most all non-integer errors. To make it compliant,
// we would simply need to change the mantissa to int16, but this add compiled flash space.
// Maybe update this later.
int_value = int8_t(trunc(value));
mantissa = int16_t(round(100 * (value - int_value))); // Compute mantissa for Gxx.x commands.
int_value = int8_t(truncf(value));
mantissa = lroundf(100 * (value - int_value)); // Compute mantissa for Gxx.x commands.
// NOTE: Rounding must be used to catch small floating point errors.
// Check if the g-code word is supported or errors due to modal group violations or has
// been repeated in the g-code block. If ok, update the command or record its value.
Expand Down Expand Up @@ -646,7 +651,7 @@ Error gc_execute_line(char* line, Channel& channel) {
break;
case 'N':
axis_word_bit = GCodeWord::N;
gc_block.values.n = int32_t(trunc(value));
gc_block.values.n = int32_t(truncf(value));
break;
case 'P':
axis_word_bit = GCodeWord::P;
Expand Down Expand Up @@ -771,7 +776,7 @@ Error gc_execute_line(char* line, Channel& channel) {
// [2. Set feed rate mode ]: G93 F word missing with G1,G2/3 active, implicitly or explicitly. Feed rate
// is not defined after switching to G94 from G93.
// NOTE: For jogging, ignore prior feed rate mode. Enforce G94 and check for required F word.
if (gc_parser_flags & GCParserJogMotion) {
if (jogMotion) {
if (bitnum_is_false(value_words, GCodeWord::F)) {
FAIL(Error::GcodeUndefinedFeedRate);
}
Expand Down Expand Up @@ -946,7 +951,7 @@ Error gc_execute_line(char* line, Channel& channel) {
}
}
// Select the coordinate system based on the P word
pValue = int8_t(trunc(gc_block.values.p)); // Convert p value to integer
pValue = int8_t(truncf(gc_block.values.p)); // Convert p value to integer
if (pValue > 0) {
// P1 means G54, P2 means G55, etc.
coord_select = static_cast<CoordIndex>(pValue - 1 + int(CoordIndex::G54));
Expand Down Expand Up @@ -1102,7 +1107,7 @@ Error gc_execute_line(char* line, Channel& channel) {
}
break;
case Motion::CwArc:
gc_parser_flags |= GCParserArcIsClockwise; // No break intentional.
clockwiseArc = true; // No break intentional.
case Motion::CcwArc:
// [G2/3 Errors All-Modes]: Feed rate undefined.
// [G2/3 Radius-Mode Errors]: No axis words in selected plane. Target point is same as current.
Expand Down Expand Up @@ -1247,11 +1252,11 @@ Error gc_execute_line(char* line, Channel& channel) {
break;
case Motion::ProbeTowardNoError:
case Motion::ProbeAwayNoError:
gc_parser_flags |= GCParserProbeIsNoError; // No break intentional.
probeNoError = true; // No break intentional.
case Motion::ProbeToward:
case Motion::ProbeAway:
if ((gc_block.modal.motion == Motion::ProbeAway) || (gc_block.modal.motion == Motion::ProbeAwayNoError)) {
gc_parser_flags |= GCParserProbeIsAway;
probeAway = true;
}
// [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate
// is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning
Expand Down Expand Up @@ -1279,7 +1284,7 @@ Error gc_execute_line(char* line, Channel& channel) {
// [21. Program flow ]: No error checks required.
// [0. Non-specific error-checks]: Complete unused value words check, i.e. IJK used when in arc
// radius mode, or axis words that aren't used in the block.
if (gc_parser_flags & GCParserJogMotion) {
if (jogMotion) {
// Jogging only uses the F feed rate and XYZ value words. N is valid, but S and T are invalid.
clear_bits(value_words, (bitnum_to_mask(GCodeWord::N) | bitnum_to_mask(GCodeWord::F)));
} else {
Expand Down Expand Up @@ -1308,7 +1313,7 @@ Error gc_execute_line(char* line, Channel& channel) {
// NOTE: G-code parser state is not updated, except the position to ensure sequential jog
// targets are computed correctly. The final parser position after a jog is updated in
// protocol_execute_realtime() when jogging completes or is canceled.
if (gc_parser_flags & GCParserJogMotion) {
if (jogMotion) {
// Only distance and unit modal commands and G53 absolute override command are allowed.
// NOTE: Feed rate word and axis word checks have already been performed in STEP 3.
if (command_words & ~(bitnum_to_mask(ModalGroup::MG3) | bitnum_to_mask(ModalGroup::MG6) | bitnum_to_mask(ModalGroup::MG0))) {
Expand All @@ -1331,29 +1336,37 @@ Error gc_execute_line(char* line, Channel& channel) {
}
// If in laser mode, setup laser power based on current and past parser conditions.
if (spindle->isRateAdjusted()) {
if (!((gc_block.modal.motion == Motion::Linear) || (gc_block.modal.motion == Motion::CwArc) ||
(gc_block.modal.motion == Motion::CcwArc))) {
if (gc_state.modal.spindle == SpindleState::Ccw)
gc_parser_flags |= GCParserLaserDisable;
bool blockIsFeedrateMotion = (gc_block.modal.motion == Motion::Linear) || (gc_block.modal.motion == Motion::CwArc) ||
(gc_block.modal.motion == Motion::CcwArc);
bool stateIsFeedrateMotion = (gc_state.modal.motion == Motion::Linear) || (gc_state.modal.motion == Motion::CwArc) ||
(gc_state.modal.motion == Motion::CcwArc);

if (!blockIsFeedrateMotion) {
// If the new mode is not a feedrate move (G1/2/3) we want the laser off
disableLaser = true;
// If we are changing from a feedrate move to a non-feedrate move,
// we must sync the planner and then update the laser state
if (stateIsFeedrateMotion) {
syncLaser = true;
}
}
// Any motion mode with axis words is allowed to be passed from a spindle speed update.
// NOTE: G1 and G0 without axis words sets axis_command to none. G28/30 are intentionally omitted.
// TODO: Check sync conditions for M3 enabled motions that don't enter the planner. (zero length).
if (axis_words && (axis_command == AxisCommand::MotionMode)) {
gc_parser_flags |= GCParserLaserIsMotion;
if (blockIsFeedrateMotion && axis_words && (axis_command == AxisCommand::MotionMode)) {
laserIsMotion = true;
} else {
// M3 constant power laser requires planner syncs to update the laser when changing between
// a G1/2/3 motion mode state and vice versa when there is no motion in the line.
if (gc_state.modal.spindle == SpindleState::Cw) {
if ((gc_state.modal.motion == Motion::Linear) || (gc_state.modal.motion == Motion::CwArc) ||
(gc_state.modal.motion == Motion::CcwArc)) {
if (bits_are_true(gc_parser_flags, GCParserLaserDisable)) {
gc_parser_flags |= GCParserLaserForceSync; // Change from G1/2/3 motion mode.
if (stateIsFeedrateMotion) {
if (disableLaser) {
syncLaser = true; // Change from G1/2/3 motion mode.
}
} else {
// When changing to a G1 motion mode without axis words from a non-G1/2/3 motion mode.
if (bits_are_false(gc_parser_flags, GCParserLaserDisable)) {
gc_parser_flags |= GCParserLaserForceSync;
if (!disableLaser) {
syncLaser = true;
}
}
}
Expand All @@ -1374,24 +1387,20 @@ Error gc_execute_line(char* line, Channel& channel) {
gc_state.feed_rate = gc_block.values.f; // Always copy this value. See feed rate error-checking.
pl_data->feed_rate = gc_state.feed_rate; // Record data for planner use.
// [4. Set spindle speed ]:
if ((gc_state.spindle_speed != gc_block.values.s) || bits_are_true(gc_parser_flags, GCParserLaserForceSync)) {
if ((gc_state.spindle_speed != gc_block.values.s) || syncLaser) {
if (gc_state.modal.spindle != SpindleState::Disable) {
if (bits_are_false(gc_parser_flags, GCParserLaserIsMotion)) {
if (!laserIsMotion) {
if (sys.state != State::CheckMode) {
protocol_buffer_synchronize();
if (bits_are_true(gc_parser_flags, GCParserLaserDisable)) {
spindle->setState(gc_state.modal.spindle, 0);
} else {
spindle->setState(gc_state.modal.spindle, (uint32_t)gc_block.values.s);
}
spindle->setState(gc_state.modal.spindle, disableLaser ? 0 : (uint32_t)gc_block.values.s);
report_ovr_counter = 0; // Set to report change immediately
}
}
}
gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state.
}
// NOTE: Pass zero spindle speed for all restricted laser motions.
if (bits_are_false(gc_parser_flags, GCParserLaserDisable)) {
if (!disableLaser) {
pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use.
} // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already.
// [5. Select tool ]: NOT SUPPORTED. Only tracks tool value.
Expand All @@ -1408,8 +1417,8 @@ Error gc_execute_line(char* line, Channel& channel) {
if (sys.state != State::CheckMode) {
protocol_buffer_synchronize();
spindle->setState(gc_block.modal.spindle, (uint32_t)pl_data->spindle_speed);
report_ovr_counter = 0; // Set to report change immediately
}
report_ovr_counter = 0; // Set to report change immediately
gc_state.modal.spindle = gc_block.modal.spindle;
}
pl_data->spindle = gc_state.modal.spindle;
Expand Down Expand Up @@ -1577,14 +1586,14 @@ Error gc_execute_line(char* line, Channel& channel) {
axis_0,
axis_1,
axis_linear,
bits_are_true(gc_parser_flags, GCParserArcIsClockwise));
clockwiseArc);
} else {
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
// upon a successful probing cycle, the machine position and the returned value should be the same.
if (!ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES) {
pl_data->motion.noFeedOverride = 1;
}
gc_update_pos = mc_probe_cycle(gc_block.values.xyz, pl_data, gc_parser_flags, axis_words, gc_block.values.p);
gc_update_pos = mc_probe_cycle(gc_block.values.xyz, pl_data, probeAway, probeNoError, axis_words, gc_block.values.p);
}
// As far as the parser is concerned, the position is now == target. In reality the
// motion control system might still be processing the action and the real tool position
Expand Down
13 changes: 0 additions & 13 deletions FluidNC/src/GCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,6 @@ enum class GCUpdatePos : uint8_t {
None = 2,
};

// GCode parser flags for handling special cases.
enum GCParserFlags {
GCParserNone = 0, // Must be zero.
GCParserJogMotion = bitnum_to_mask(0),
GCParserCheckMantissa = bitnum_to_mask(1),
GCParserArcIsClockwise = bitnum_to_mask(2),
GCParserProbeIsAway = bitnum_to_mask(3),
GCParserProbeIsNoError = bitnum_to_mask(4),
GCParserLaserForceSync = bitnum_to_mask(5),
GCParserLaserDisable = bitnum_to_mask(6), // disable laser when motion stops
GCParserLaserIsMotion = bitnum_to_mask(7), //
};

// Various places in the code access saved coordinate system data
// by a small integer index according to the values below.
enum CoordIndex : uint8_t {
Expand Down
10 changes: 4 additions & 6 deletions FluidNC/src/MotionControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ bool probe_succeeded = false;

// Perform tool length probe cycle. Requires probe switch.
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_flags, uint8_t offsetAxis, float offset) {
GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, bool away, bool no_error, uint8_t offsetAxis, float offset) {
if (!config->_probe->exists()) {
log_error("Probe pin is not configured");
return GCUpdatePos::None;
Expand All @@ -309,10 +309,8 @@ GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t par
config->_stepping->beginLowLatency();

// Initialize probing control variables
bool is_probe_away = bits_are_true(parser_flags, GCParserProbeIsAway);
bool is_no_error = bits_are_true(parser_flags, GCParserProbeIsNoError);
probe_succeeded = false; // Re-initialize probe history before beginning cycle.
config->_probe->set_direction(is_probe_away);
probe_succeeded = false; // Re-initialize probe history before beginning cycle.
config->_probe->set_direction(away);
// After syncing, check if probe is already triggered. If so, halt and issue alarm.
// NOTE: This probe initialization error applies to all probing cycles.
if (config->_probe->tripped()) {
Expand Down Expand Up @@ -341,7 +339,7 @@ GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t par
// Probing cycle complete!
// Set state variables and error out, if the probe failed and cycle with error is enabled.
if (probeState == ProbeState::Active) {
if (is_no_error) {
if (no_error) {
copyAxes(probe_steps, get_motor_steps());
} else {
rtAlarm = ExecAlarm::ProbeFailContact;
Expand Down
2 changes: 1 addition & 1 deletion FluidNC/src/MotionControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ bool mc_dwell(int32_t milliseconds);
void mc_homing_cycle(AxisMask cycle_mask);

// Perform tool length probe cycle. Requires probe switch.
GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t parser_flags, uint8_t offsetAxis = 0, float offset = 0.0);
GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, bool away, bool no_error, uint8_t offsetAxis, float offset);

// Handles updating the override control state.
void mc_override_ctrl_update(Override override_state);
Expand Down
Loading

0 comments on commit f02a972

Please sign in to comment.