diff --git a/src/modules/pulse_gen.cpp b/src/modules/pulse_gen.cpp index 788977e..d06d1d0 100644 --- a/src/modules/pulse_gen.cpp +++ b/src/modules/pulse_gen.cpp @@ -96,14 +96,15 @@ bool PulseGen::PlanMoveTo(pos_t target, steps_t feed_rate, steps_t end_rate) { block_t *block = &block_buffer[block_index.back()]; // Bail if this is a zero-length block - block->steps = abs(target - position); + pos_t steps = target - position; + block->steps = abs(steps); if (block->steps <= config::dropSegments) { // behave as-if the block has been scheduled return true; } // Direction and speed for this block - block->direction = (target >= position); + block->direction = steps >= 0; block->nominal_rate = feed_rate; // Acceleration of the segment, in steps/sec^2 diff --git a/src/modules/pulse_gen.h b/src/modules/pulse_gen.h index e189a66..440151c 100644 --- a/src/modules/pulse_gen.h +++ b/src/modules/pulse_gen.h @@ -195,16 +195,19 @@ private: /// Calculate the trapezoid parameters for the block void CalculateTrapezoid(block_t *block, steps_t entry_speed, steps_t exit_speed); + /// Return the axis shift introduced by the specified full block + static inline pos_t BlockShift(const block_t *block) { + return block->direction ? block->steps : -block->steps; + } + +#ifdef UNITTEST_MOTION +public: +#endif /// Return the axis shift introduced by the current (live) block inline pos_t CurBlockShift() const { steps_t steps_missing = (current_block->steps - steps_completed); return current_block->direction ? steps_missing : -steps_missing; } - - /// Return the axis shift introduced by the specified full block - static inline pos_t BlockShift(const block_t *block) { - return block->direction ? block->steps : -block->steps; - } }; } // namespace pulse_gen diff --git a/tests/unit/modules/motion/test_motion.cpp b/tests/unit/modules/motion/test_motion.cpp index 3317243..d60dce9 100644 --- a/tests/unit/modules/motion/test_motion.cpp +++ b/tests/unit/modules/motion/test_motion.cpp @@ -278,3 +278,27 @@ TEST_CASE("motion::long_pulley_move", "[motion]") { motion.PlanMoveTo(mm400, 1._mm_s); REQUIRE(stepUntilDone() == p); } + +TEST_CASE("motion::pos_overflow", "[motion]") { + ResetMotionSim(); + + // set a position _at_ the overflow limit + mm::pos_t pos_max = std::numeric_limits::max(); + mm::motion.SetPosition(mm::Pulley, pos_max); + REQUIRE(mm::motion.Position(mm::Pulley) == pos_max); + + // plan a move which will overflow + mm::pos_t steps = 10; + mm::motion.PlanMove(mm::Pulley, steps, 1); + + // ensure we did overflow + REQUIRE(mm::motion.Position(mm::Pulley) < pos_max); + + // step once to setup current_block + mm::motion.Step(); + + // ensure the move direction and step count is correct despite the overflow + // abuse CurBlockShift to get both, accounting for the useless single step + // we performed just above. + REQUIRE(mm::motion.CtrlForAxis(mm::Pulley).CurBlockShift() == steps - 1); +}