24 #include "GrblAxis.hpp"
26 #include <ccut/Regex.hpp>
27 #include <ccut/async.hpp>
29 #include "GrblPlatform.hpp"
30 #include "util/grbl/GrblDeviceBase.hpp"
31 #include "util/grbl/GrblGenerator.hpp"
33 using namespace logger;
35 using namespace smc::internal;
36 using namespace std::chrono;
42 GrblAxis::GrblAxis(
const std::string &uid,
43 const std::shared_ptr<GrblPlatform> &grbl) :
48 std::future<void> GrblAxis::moveTo(
const units::Value &userPosition)
const
52 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
54 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
56 grbl::Axis grblAxis = grbl->getAxis(
uid());
58 if (!
convert(pos, units::unit_t::millimeters))
59 throw Exception(ErrorCode::IncompatibleUnits,
60 "failed to convert in millimeters");
63 gen << grbl::gen::MotionMode::Rapid << grbl::gen::DistanceMode::Absolute
68 cmd.line = ++ctx.line;
69 std::string msg = cmd.message;
71 if (ctx.triggeredMotion)
73 uint8_t trigPin = grbl->getTrigger(ctx.prefix + ctx.id);
74 msg += grbl::gen::DigitalOut::on(trigPin, false).value;
78 msg +=
"(MSG,Stepper:NewBlock)";
80 grbl::ErrorCode code = ctx.device->send(msg);
83 std::set<grbl::Axis>{grblAxis}, gen.str());
84 return grbl->queue(std::move(cmd));
88 return ccut::make_future_error(ex);
96 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
98 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
100 grbl::Axis grblAxis = grbl->getAxis(
uid());
102 if (!
convert(pos, units::unit_t::millimeters))
103 throw Exception(ErrorCode::IncompatibleUnits,
104 "failed to convert in millimeters");
107 gen << grbl::gen::MotionMode::Rapid << grbl::gen::DistanceMode::Relative
112 cmd.line = ++ctx.line;
113 std::string msg = cmd.message;
115 if (ctx.triggeredMotion)
117 uint8_t trigPin = grbl->getTrigger(ctx.prefix + ctx.id);
118 msg += grbl::gen::DigitalOut::on(trigPin, false).value;
122 msg +=
"(MSG,Stepper:NewBlock)";
124 grbl::ErrorCode code = ctx.device->send(msg);
127 std::set<grbl::Axis>{grblAxis}, gen.str());
128 return grbl->queue(std::move(cmd));
132 return ccut::make_future_error(ex);
136 void GrblPlatform::Context::sendHold()
138 this->
checkReply(this->device->sendRealtime(grbl::gen::Realtime::FeedHold));
139 const steady_clock::time_point deadline = steady_clock::now() + seconds{30};
141 while (steady_clock::now() <= deadline)
144 grbl::gen::Realtime::StatusReport,
145 [
this](
const std::string &message) {
146 if (grbl::GrblParser::getLineType(message) ==
147 grbl::LineType::State)
149 this->device->dataSignal(message);
150 throw grbl::ErrorCode{0};
155 if (st.runState == grbl::RunState::Hold &&
157 grbl::HoldStateArg::Complete)
163 std::this_thread::sleep_for(std::chrono::milliseconds{100});
166 std::ostringstream oss;
167 oss <<
"Failed to pause motion (state=" <<
grbl::to_string(state.runState)
168 <<
":" << state.runStateArg <<
")";
169 throw Exception(ErrorCode::Runtime, oss.str());
176 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
178 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
180 std::future<void> f = grbl->run<
void>(
183 grbl->clearQueues(
"stopped",
false);
185 cmd.prom->get<
void>().set_value();
191 return ccut::make_future_error<void>(ex);
199 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
201 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
203 std::future<void> f = grbl->run<
void>(
206 cmd.prom->get<
void>().set_value();
212 return ccut::make_future_error<void>(ex);
220 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
222 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
224 std::future<void> f = grbl->run<
void>(
227 ctx.device->sendRealtime(grbl::gen::Realtime::CycleStart));
228 cmd.prom->get<
void>().set_value();
234 return ccut::make_future_error<void>(ex);
242 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
244 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
246 std::shared_ptr<const Axis> obj{
247 std::static_pointer_cast<const Axis>(shared_from_this())};
251 ctx.device->sendRealtime(
252 grbl::gen::Realtime::StatusReport,
253 [&ctx](
const std::string &message) {
255 grbl::LineType::State)
257 ctx.device->dataSignal(message);
258 throw grbl::ErrorCode{0};
263 obj->lastPosition(unit));
269 return ccut::make_future_error<units::value_t>(ex);
278 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
280 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
282 grbl::Axis grblAxis = grbl->getAxis(
uid());
285 if (!
convert(pos, units::unit_t::millimeters))
286 throw Exception(ErrorCode::IncompatibleUnits,
287 "failed to convert in millimeters");
289 std::future<void> f = grbl->run<
void>(
294 grbl::grbl_float_t(pos.value)};
295 grbl::ErrorCode code = ctx.device->send(gen.str());
296 ctx.checkReply(code);
298 cmd.prom->get<
void>().set_value();
304 return ccut::make_future_error(ex);
312 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
314 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
316 ret = grbl->getLastAxisPosition(
uid());
318 if (ret.unit != unit)
321 throw Exception(ErrorCode::IncompatibleUnits,
322 "failed to convert to " +
to_string(unit));
327 static const ccut::Regex alarmCodeRegex{
"ALARM:([[:digit:]]+)"};
330 const std::chrono::milliseconds &timeout)
const
334 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
336 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
339 std::future<void> f = grbl->run<
void>(
342 grbl::ErrorCode code = ctx.device->send(
343 grbl::gen::System::Home,
344 [&ctx](
const std::string &line) {
345 std::vector<std::string> matches;
346 if (alarmCodeRegex.match(line, matches))
348 int code = std::stoi(matches[1].c_str());
349 std::string alarm_msg = ctx.getAlarmMessage(
350 static_cast<grbl::AlarmCode
>(code));
351 error(GrblPlatform::s_loggerCat) << alarm_msg;
352 throw grbl::CustomErrorCode::InternalError;
358 if (code == grbl::CustomErrorCode::Timeout)
360 error(GrblPlatform::s_loggerCat)
361 <<
"homing request timeout";
362 grbl->clearQueues(
"homing failed",
false);
365 ctx.checkReply(code);
367 cmd.prom->get<
void>().set_value();
373 return ccut::make_future_error<void>(ex);
377 static Axis::State grblStateToAxisState(
const grbl::RunState &state)
381 case grbl::RunState::Idle:
return Axis::State::IDLE;
382 case grbl::RunState::Run:
383 case grbl::RunState::Hold:
384 case grbl::RunState::Jog:
385 case grbl::RunState::Home:
return Axis::State::RUNNING;
386 case grbl::RunState::Alarm:
return Axis::State::ERROR;
387 default:
return Axis::State::UNKNOWN;
395 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
397 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
399 std::future<Axis::State> f = grbl->run<
Axis::State>(
401 grbl::RunState grblState = ctx.state.runState;
402 Axis::State runState = grblStateToAxisState(grblState);
409 return ccut::make_future_error<Axis::State>(ex);
417 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
419 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
421 grbl::Axis grblAxis = grbl->getAxis(
uid());
422 return grbl->run<std::set<std::string>>(
424 cmd.prom->get<std::set<std::string>>().set_value(
425 ctx.listConfig(grblAxis));
430 return ccut::make_future_error<std::set<std::string>>(ex);
438 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
440 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
442 const std::string
uid = this->
uid();
444 grbl::Axis grblAxis = grbl->getAxis(
uid);
445 return grbl->run<std::string>([name, grblAxis,
uid,
448 grbl::SettingId
id = ctx.findSetting(name, grblAxis).id;
450 grbl::ErrorCode rc = ctx.device->send(
451 grbl::gen::System::getSetting(
id),
452 [id,
uid, &ret, grbl](
const std::string &line) {
453 if (GrblParser::getLineType(line) == grbl::LineType::Setting)
455 GrblParser::Setting setting;
456 if ((GrblParser::parseSetting(line, setting)) &&
457 (setting.first == id))
459 ret = setting.second;
460 grbl->updateAxisSetting(
uid, setting.first,
469 cmd.prom->get<std::string>().set_value(ret);
474 return ccut::make_future_error<std::string>(ex);
479 const std::string &value)
const
483 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
485 throw Exception(ErrorCode::Canceled,
"platform stopped (deleted)");
487 const std::string
uid = this->
uid();
488 grbl::Axis grblAxis = grbl->getAxis(
uid);
489 return grbl->run<
void>(
492 grbl::SettingId
id = ctx.findSetting(name, grblAxis).id;
493 grbl::ErrorCode rc = ctx.device->send(
494 grbl::gen::System::setSetting(
id, value));
496 grbl->updateAxisSetting(
uid,
id, value);
497 cmd.prom->get<
void>().set_value();
502 return ccut::make_future_error(ex);
514 std::shared_ptr<GrblPlatform> grbl(m_grbl.lock());
516 if (unit != value.unit && grbl)
521 if (value.unit == units::MILLIMETERS)
524 if (resolution.value <= 0)
526 logger::warning(GrblPlatform::s_loggerCat)
527 <<
"axis resolution not set";
530 value = resolution * value;
534 case units::MILLIMETERS:
535 if (value.unit == units::STEPS)
538 if (resolution.value <= 0)
540 logger::warning(GrblPlatform::s_loggerCat)
541 <<
"axis resolution not set";
544 value = value / resolution;
553 if (resolution.value <= 0)
555 logger::warning(GrblPlatform::s_loggerCat)
556 <<
"axis resolution not set";
561 case units::STEPS: value = value * resolution;
return true;
562 case units::MILLIMETERS: value = resolution / value;
return true;
563 default:
return false;
568 logger::warning(GrblPlatform::s_loggerCat)
569 <<
"failed to convert value: " << ex.what();
static LineType getLineType(const std::string &line)
detect line type
virtual bool convert(units::Value &value, units::unit_t unit) const
Convert value in a manner specific to this device.
DeviceId uid() const
Get the address of device.
Exception thrown by MotionController in case of issues with command.
std::future< State > getState() const override
Get the current axis state.
bool canConvert(const units::Value &value, units::unit_t unit) const override
Check if unit conversion is possible in a manner specific to this device.
std::future< void > resume() const override
Resume paused motion.
std::future< void > pause() const override
Pause ongoing motion, prevent queued motions from running.
std::future< void > setConfig(const std::string &name, const std::string &value) const override
set device configuration value
std::future< void > takeReference(const std::chrono::milliseconds &timeout=std::chrono::seconds{ 120}) const override
Start a homing sequence.
std::future< std::set< std::string > > listConfig() const override
list device configuration options
std::future< units::value_t > getPosition(units::unit_t unit) const override
Get current position of this axis.
units::value_t lastPosition(units::unit_t unit) const override
Get last known position of the axis.
std::future< void > setActualPosition(const units::Value &position) const override
Set current axis position.
std::future< void > stop() const override
Stop any ongoing motion, flush the motion-queue.
std::future< std::string > getConfig(const std::string &name) const override
get device configuration value
bool convert(units::Value &value, units::unit_t unit) const override
Convert value in a manner specific to this device.
std::future< void > moveBy(const units::Value &distance) const override
Move this axis by given distance.
const std::string & to_string(Axis::State state)
convert State to string
static Modal SetCoordinate(int8_t system=-1, bool current=false)
Set the Coordinate command.
HoldStateArg
Hold state argument.
main motion-lib namespace
Struct holding state of Grbl as returned by "?".
set given axis to position
void checkReply(grbl::ErrorCode code)
check command result code