25 #include "MGrblPlatform.hpp"
27 #include <ccut/Signal.hpp>
28 #include <ccut/async.hpp>
29 #include <ccut/utils.hpp>
30 #include <ccut/yml.hpp>
31 #include <logger/Logger.hpp>
33 #include "MotionLibConfig.hpp"
34 #include "platform/specialized/GrblPlatform/GrblPlatform.hpp"
35 #include "util/grbl/MGrblDeviceWrapper.hpp"
36 #include "util/grbl/MGrblSim.hpp"
38 #ifdef PLATFORM_SAMBUCA
39 #include "util/edge/MEdgeGrblDevice.hpp"
42 using namespace logger;
43 using namespace std::chrono;
44 namespace yml = ccut::yml;
49 static const std::string s_mgrblPrefix{
"grbl://"};
50 static const std::string s_loggerCat{
"smc:platform:mgrbl"};
52 MGrblPlatform::MGrblPlatform(
const ccut::yml::NodeRef &ref,
Context *data) :
53 Thread(
"MGrblPlatform"),
54 m_ctx(data ? data : new
Context{s_mgrblPrefix, ref}),
55 m_mainTriggerUrl(s_mgrblPrefix + m_ctx->id +
"/trigger")
58 yml::NodeRef deviceNode = yml::get(ref,
"device");
60 if (deviceNode.is_map())
61 yml::get(deviceNode,
"type") >> yml::default_to(type, std::string());
63 deviceNode >> yml::default_to(type, std::string());
65 if (type ==
"GrblSim")
69 #ifdef PLATFORM_SAMBUCA
70 else if (type ==
"EdgeSim")
74 yml::get(deviceNode,
"lun") >> yml::default_to(lun,
int());
75 yml::get(deviceNode,
"path") >> yml::default_to(path, std::string());
78 else if (type ==
"Edge")
81 yml::get(deviceNode,
"lun") >> yml::default_to(lun,
int());
86 throw Exception(ErrorCode::InvalidArguments,
87 "unknown MGrblPlatform device type");
89 m_ctx->device->dataSignal.connect(
90 m_dataConn, [
this](
const std::string &line) { processMessage(line); });
92 createPlatforms(*m_ctx);
97 for (
const GrblPlatform::Shared &p : m_platforms)
98 p->m_started.store(
true);
102 MGrblPlatform::~MGrblPlatform()
104 MGrblPlatform::stop();
105 m_dataConn.disconnect();
106 m_ctx->device.reset();
109 void MGrblPlatform::stop()
116 std::lock_guard<std::mutex> guard(m_lock);
117 if (m_platforms.empty())
118 throw Exception(ErrorCode::InternalError,
119 "no sub-platforms in MGrblPlatform");
121 return m_platforms[0];
128 size_t grblAxis =
static_cast<size_t>(platform->getAxis(axis.
uid()));
130 std::lock_guard<std::mutex> guard(m_lock);
131 if (m_layout.size() < grblAxis)
132 throw Exception(ErrorCode::InternalError,
"axis not in layout");
133 const mgrbl::Instance instance = m_layout[grblAxis];
135 if (instance >= m_platforms.size())
136 throw Exception(ErrorCode::InternalError,
137 "axis not bound to an instance");
139 axis.m_grbl = m_platforms[instance];
144 std::lock_guard<std::mutex> guard(m_lock);
145 if (m_platforms.empty())
146 throw Exception(ErrorCode::InternalError,
147 "no sub-platforms in MGrblPlatform");
149 const decltype(m_triggers)::const_iterator instanceId = m_triggers.find(
151 if (instanceId == m_triggers.end())
152 throw Exception(ErrorCode::InternalError,
"wrong address of trigger");
154 const mgrbl::Instance instance = instanceId->second;
155 if (instance >= m_platforms.size())
156 throw Exception(ErrorCode::InternalError,
157 "trigger not bound to an instance");
159 trigger.m_grbl = m_platforms[instance];
164 std::lock_guard<std::mutex> guard(m_lock);
166 if (m_platforms.empty())
167 throw Exception(ErrorCode::InternalError,
168 "no sub-platforms in MGrblPlatform");
170 const decltype(m_gpios)::const_iterator instanceId = m_gpios.find(
172 if (instanceId == m_gpios.end())
173 throw Exception(ErrorCode::InternalError,
"wrong address of gpio");
175 const mgrbl::Instance instance = instanceId->second;
176 if (instance >= m_platforms.size())
177 throw Exception(ErrorCode::InternalError,
178 "gpio not bound to an instance");
180 gpio.m_grbl = m_platforms[instance];
185 std::function<
void(GrblPlatform::Shared &platform,
187 bool onlyFirst)
const
192 fun(platform, *platform->m_ctx);
196 std::vector<GrblPlatform::Shared> platforms{getPlatforms()};
197 for (GrblPlatform::Shared &platform : platforms)
199 fun(platform, *platform->m_ctx);
204 void MGrblPlatform::loadLayout(Context &ctx)
206 const std::string cmd = mgrbl::ControlSymbol + mgrbl::gen::Control::Layout;
207 ctx.device->send(cmd, [
this, &ctx, &cmd](
const std::string &line) {
214 std::lock_guard<std::mutex> guard(m_lock);
217 for (mgrbl::Instance i : l)
220 info(s_loggerCat) <<
"loaded layout: " << l;
227 void MGrblPlatform::getBuildInfo(Context &ctx)
229 const std::string cmd = mgrbl::ControlSymbol +
230 mgrbl::gen::Control::BuildInfo;
231 ctx.device->send(cmd, [
this, &ctx, &cmd](
const std::string &line) {
232 info(s_loggerCat) <<
"sambuca-vitis build-info: " << line;
237 void MGrblPlatform::createPlatforms(Context &ctx)
239 const std::string cmd = mgrbl::ControlSymbol +
240 mgrbl::gen::Control::GrblCount;
242 ctx.device->send(cmd, [
this, &cmd](
const std::string &line) {
243 if (ccut::startsWith(line, cmd))
245 std::lock_guard<std::mutex> guard(m_lock);
246 m_platforms.reserve(std::stoi(line.substr(cmd.size() + 1)));
254 std::lock_guard<std::mutex> guard(m_lock);
255 capacity = m_platforms.capacity();
259 throw Exception(ErrorCode::InvalidArguments,
260 "failed to retrieve MGrblPlatform instances count");
262 for (
size_t i = 0; i < capacity; ++i)
264 GrblPlatform::Shared grbl{
265 new GrblPlatform(ctx.prefix, ctx.id,
266 std::unique_ptr<grbl::GrblDeviceBase>(
270 grbl->m_ctx->sendReset();
272 std::lock_guard<std::mutex> guard(m_lock);
273 m_platforms.emplace_back(grbl);
277 void MGrblPlatform::thread_func()
279 debug(s_loggerCat) <<
"started";
280 m_ctx->nextPoll = steady_clock::now();
281 const milliseconds interval = GrblPlatform::defaultInterval;
283 std::vector<GrblPlatform::Shared> platforms = getPlatforms();
287 if (platforms.empty())
288 throw Exception(ErrorCode::InternalError,
289 "no sub-platforms in MGrblPlatform");
292 GrblPlatform::Shared first = platforms.front();
295 first->loadSettingsDesc();
296 for (
const GrblPlatform::Shared &p : platforms)
300 p->m_ctx->errors = first->m_ctx->errors;
301 p->m_ctx->alarms = first->m_ctx->alarms;
302 p->m_ctx->setting = first->m_ctx->setting;
303 p->m_ctx->settingGroup = first->m_ctx->settingGroup;
309 while (m_started.load())
311 steady_clock::time_point now = steady_clock::now();
312 const milliseconds timeout = (now < m_ctx->nextPoll) ?
313 duration_cast<milliseconds>(m_ctx->nextPoll - now) :
314 milliseconds::zero();
316 m_ctx->device->fetch(timeout);
318 while (processImmediate(*m_ctx))
321 for (
const GrblPlatform::Shared &p : platforms)
324 while (p->processImmediate())
330 now = steady_clock::now();
331 if (m_ctx->nextPoll <= now)
334 m_ctx->nextPoll = now + interval;
338 catch (Exception &ex)
340 crit(s_loggerCat) << ex.what();
341 crit(s_loggerCat) <<
"stopping thread";
342 m_started.store(
false);
345 for (
const GrblPlatform::Shared &p : platforms)
347 p->m_started.store(
false);
348 p->clearQueues(
"platform stopped");
350 clearQueue(
"platform stopped");
353 void MGrblPlatform::clearQueue(
const std::string &msg)
355 info(s_loggerCat) <<
"clearing run-queues";
356 std::unique_lock<std::mutex> lock(m_lock);
357 while (!m_immediate.empty())
361 cmd.prom->set_exception(Exception(ErrorCode::Canceled, msg));
367 std::string msg(
"0?");
368 for (mgrbl::Instance i : ctx.used)
370 msg[0] =
static_cast<char>(i +
'0');
371 ctx.device->sendRealtime(msg);
375 bool MGrblPlatform::processImmediate(Context &ctx)
377 std::unique_lock<std::mutex> lock(m_lock);
378 if (m_immediate.empty())
390 cmd.prom->set_exception(ex);
392 catch (std::exception &ex)
394 cmd.prom->set_exception(Exception(ErrorCode::Runtime, ex.what()));
399 void MGrblPlatform::wake()
401 std::lock_guard<std::mutex> lock(m_mutex);
404 m_ctx->device->wake();
407 void MGrblPlatform::processMessage(
const std::string &message)
413 notice(s_loggerCat) <<
"<~~ " << message;
417 const std::string instanceMessage{message.substr(1)};
419 if (GrblPlatform::Context::isStepperMessage(instanceMessage))
420 m_ctx->nextPoll = steady_clock::now();
423 p->m_ctx->device->dataSignal(instanceMessage);
425 catch (Exception &ex)
427 error(s_loggerCat) <<
"failed to processMessage: " << ex.what();
431 MGrblAxis::Shared MGrblPlatform::createAxis(
432 const std::string &uid,
433 const std::shared_ptr<GrblPlatform> &grbl)
435 return std::make_shared<MGrblAxis>(uid, shared_from_this(), grbl);
Class for implementing Multi-Grbl functionality on top of GrblDeviceBase.
static Instance getInstance(const std::string &line)
return line instance
static bool isControl(const std::string &line)
check if given line is control
static bool parseLayout(const std::string &line, Layout &layout)
parse layout reply
DeviceId uid() const
Get the address of device.
Exception thrown by MotionController in case of issues with command.
main motion-lib namespace